diff --git a/packages/nitro/src/build.ts b/packages/nitro/src/build.ts new file mode 100644 index 0000000000..1c60dad82c --- /dev/null +++ b/packages/nitro/src/build.ts @@ -0,0 +1,80 @@ +import { resolve } from 'path' +import consola from 'consola' +import { rollup, OutputOptions } from 'rollup' +import Hookable from 'hookable' +import defu from 'defu' +import prettyBytes from 'pretty-bytes' +import gzipSize from 'gzip-size' +import chalk from 'chalk' +import { copy, emptyDir, existsSync } from 'fs-extra' +import { getRollupConfig } from './rollup/config' +import { tryImport, hl, prettyPath, renderTemplate, compileTemplateToJS } from './utils' + +export async function build (baseConfig, target) { + consola.info(`Generating bundle for ${hl(target.target)}`) + + const _targetDefaults = tryImport(__dirname, `./targets/${target.target}`) || + tryImport(baseConfig.rootDir, target.target) + if (!_targetDefaults) { + throw new Error('Cannot resolve target: ' + target.target) + } + + const config: any = defu( + // Target specific config by user + target, + // Global user config + baseConfig, + // Target defaults + _targetDefaults, + // Generic defaults + { outDir: resolve(baseConfig.buildDir, `dist/${target.target}`), outName: 'index.js' } + ) + + const hooks = new Hookable() + hooks.addHooks(config.hooks) + + await hooks.callHook('config', config) + + emptyDir(config.outDir) + + config.rollupConfig = getRollupConfig(config) + await hooks.callHook('rollup:before', config) + const build = await rollup(config.rollupConfig) + + const { output } = await build.write(config.rollupConfig.output as OutputOptions) + const size = prettyBytes(output[0].code.length) + const zSize = prettyBytes(await gzipSize(output[0].code)) + consola.success('Generated', prettyPath((config.rollupConfig.output as any).file), + chalk.gray(`(Size: ${size} Gzip: ${zSize})`) + ) + + for (const tmpl of config.templates) { + const dstPath = resolve(config.outDir, tmpl.dst) + await renderTemplate(tmpl.src, dstPath, { config }) + consola.info('Compiled', prettyPath(dstPath)) + } + + if (config.copyAssets) { + const publicDir = typeof config.copyAssets === 'string' ? config.copyAssets : 'public' + const dst = resolve(config.outDir, publicDir, '_nuxt') + await copy(resolve(config.buildDir, 'dist/client'), dst) + consola.info('Copied public assets to', prettyPath(dst)) + } + + await hooks.callHook('done', config) +} + +export async function compileHTMLTemplate (baseConfig) { + const htmlTemplateFile = resolve(baseConfig.buildDir, `views/${{ 2: 'app', 3: 'document' }[baseConfig.nuxt]}.template.html`) + const htmlTemplateFileJS = htmlTemplateFile.replace(/.html$/, '.js').replace('app.', 'document.') + await compileTemplateToJS(htmlTemplateFile, htmlTemplateFileJS) + consola.info('Generated', prettyPath(htmlTemplateFileJS)) +} + +export function ensureDist (baseConfig) { + if (!existsSync(resolve(baseConfig.buildDir, 'dist/server'))) { + return consola.error('Please use `nuxt build` first to build project!') + } else { + consola.success('Using existing nuxt build from', prettyPath(baseConfig.buildDir)) + } +} diff --git a/packages/nitro/src/cli.ts b/packages/nitro/src/cli.ts index b048857b45..11558f595c 100644 --- a/packages/nitro/src/cli.ts +++ b/packages/nitro/src/cli.ts @@ -1,117 +1,26 @@ import { resolve } from 'path' -import { rollup, OutputOptions } from 'rollup' import consola from 'consola' -import Hookable from 'hookable' -import defu from 'defu' -import { existsSync, copy, emptyDir } from 'fs-extra' -import prettyBytes from 'pretty-bytes' -import gzipSize from 'gzip-size' -import chalk from 'chalk' -import { getRollupConfig } from './rollup/config' -import { tryImport, hl, prettyPath, compileTemplateToJS, renderTemplate } from './utils' +import { build, compileHTMLTemplate, ensureDist } from './build' +import { getBaseConfig } from './config' async function _runCLI () { const rootDir = resolve(process.cwd(), process.argv[2] || '.') // Config - const config = { - rootDir, - buildDir: '', - targets: [], - templates: [], - nuxt: 2, - target: process.argv[3] && process.argv[3][0] !== '-' ? process.argv[3] : null, - minify: process.argv.includes('--minify') ? true : null, - analyze: process.argv.includes('--analyze') ? true : null, - logStartup: true - } - - Object.assign(config, tryImport(rootDir, './nuxt.config')!.serverless) - - config.buildDir = resolve(config.rootDir, config.buildDir || '.nuxt') - - config.targets = config.targets.map(t => typeof t === 'string' ? { target: t } : t) - if (config.target && !config.targets.find(t => t.target === config.target)) { - config.targets.push({ target: config.target }) - } + const baseConfig = getBaseConfig(rootDir) // Ensure dist exists - if (!existsSync(resolve(config.buildDir, 'dist/server'))) { - return consola.error('Please use `nuxt build` first to build project!') - } else { - consola.success('Using existing nuxt build from', prettyPath(config.buildDir)) - } - - // Ensure relative operations are relative to build dir (fixes rollup dynamic imports) - process.chdir(config.buildDir) + await ensureDist(baseConfig) // Compile html template - const htmlTemplateFile = resolve(config.buildDir, `views/${{ 2: 'app', 3: 'document' }[config.nuxt]}.template.html`) - const htmlTemplateFileJS = htmlTemplateFile.replace(/.html$/, '.js').replace('app.', 'document.') - await compileTemplateToJS(htmlTemplateFile, htmlTemplateFileJS) - consola.info('Generated', prettyPath(htmlTemplateFileJS)) + await compileHTMLTemplate(baseConfig) // Bundle for each target - for (let target of config.targets) { - if (typeof target === 'string') { - target = { target } - } - - if (config.target && target.target !== config.target) { + for (const target of baseConfig.targets) { + if (baseConfig.target && target.target !== baseConfig.target) { continue } - - consola.info(`Generating bundle for ${hl(target.target)}`) - - const _targetDefaults = tryImport(__dirname, `./targets/${target.target}`) || tryImport(config.rootDir, target.target) - if (!_targetDefaults) { - consola.warn('Cannot resolve target', target.target) - continue - } - - const _config: any = defu( - // Target specific config by user - target, - // Global user config - config, - // Target defaults - _targetDefaults, - // Generic defaults - { outDir: resolve(config.buildDir, `dist/${target.target}`), outName: 'index.js' } - ) - - const hooks = new Hookable() - hooks.addHooks(_config.hooks) - - await hooks.callHook('config', _config) - - emptyDir(_config.outDir) - - _config.rollupConfig = getRollupConfig(_config) - await hooks.callHook('rollup:before', _config) - const build = await rollup(_config.rollupConfig) - - const { output } = await build.write(_config.rollupConfig.output as OutputOptions) - const size = prettyBytes(output[0].code.length) - const zSize = prettyBytes(await gzipSize(output[0].code)) - consola.success('Generated', prettyPath((_config.rollupConfig.output as any).file), - chalk.gray(`(Size: ${size} Gzip: ${zSize})`) - ) - - for (const tmpl of _config.templates) { - const dstPath = resolve(_config.outDir, tmpl.dst) - await renderTemplate(tmpl.src, dstPath, { config: _config }) - consola.info('Compiled', prettyPath(dstPath)) - } - - if (_config.copyAssets) { - const publicDir = typeof _config.copyAssets === 'string' ? _config.copyAssets : 'public' - const dst = resolve(_config.outDir, publicDir, '_nuxt') - await copy(resolve(_config.buildDir, 'dist/client'), dst) - consola.info('Copied public assets to', prettyPath(dst)) - } - - await hooks.callHook('done', _config) + await build(baseConfig, target) } } diff --git a/packages/nitro/src/config.ts b/packages/nitro/src/config.ts new file mode 100644 index 0000000000..33445067ce --- /dev/null +++ b/packages/nitro/src/config.ts @@ -0,0 +1,27 @@ +import { resolve } from 'path' +import { tryImport } from './utils' + +export function getBaseConfig (rootDir) { + const baseConfig = { + rootDir, + buildDir: '', + targets: [], + templates: [], + nuxt: 2, + target: process.argv[3] && process.argv[3][0] !== '-' ? process.argv[3] : null, + minify: process.argv.includes('--minify') ? true : null, + analyze: process.argv.includes('--analyze') ? true : null, + logStartup: true + } + + Object.assign(baseConfig, tryImport(rootDir, './nuxt.config')!.serverless) + + baseConfig.buildDir = resolve(baseConfig.rootDir, baseConfig.buildDir || '.nuxt') + + baseConfig.targets = baseConfig.targets.map(t => typeof t === 'string' ? { target: t } : t) + if (baseConfig.target && !baseConfig.targets.find(t => t.target === baseConfig.target)) { + baseConfig.targets.push({ target: baseConfig.target }) + } + + return baseConfig +}