diff --git a/packages/nitro/src/dynamic-require.ts b/packages/nitro/src/dynamic-require.ts new file mode 100644 index 0000000000..c2d4894cfd --- /dev/null +++ b/packages/nitro/src/dynamic-require.ts @@ -0,0 +1,46 @@ +import { resolve } from 'path' +import globby, { GlobbyOptions } from 'globby' + +const PLUGIN_NAME = 'dynamic-require' +const HELPER_DYNAMIC = `\0${PLUGIN_NAME}.js` +const DYNAMIC_REQUIRE_RE = /require\("\.\/" \+/g + +function CJSTemplate ({ imports }) { + return `${imports.map(i => `import ${i.name} from '${i.import}'`).join('\n')} +const dynamicChunks = { + ${imports.map(i => ` ['${i.id}']: ${i.name}`).join(',\n')} +}; + +export default function dynamicRequire(id) { + return dynamicChunks[id]; +};` +} + +interface Options { + dir: string, + globbyOptions: GlobbyOptions +} + +export default function dynamicRequire ({ dir, globbyOptions }: Options) { + return { + name: PLUGIN_NAME, + transform (code, _id) { + return code.replace(DYNAMIC_REQUIRE_RE, `require('${HELPER_DYNAMIC}')(`) + }, + resolveId (id) { + return id === HELPER_DYNAMIC ? id : null + }, + async load (id) { + if (id === HELPER_DYNAMIC) { + const files = await globby('**/*.js', { cwd: dir, absolute: false, ...globbyOptions }) + const imports = files.map(id => ({ + id, + import: resolve(dir, id), + name: id.replace(/[\\/.]/g, '_') + })) + return CJSTemplate({ imports }) + } + return null + } + } +} diff --git a/packages/nitro/src/dynamic.ts b/packages/nitro/src/dynamic.ts deleted file mode 100644 index 2209ce7519..0000000000 --- a/packages/nitro/src/dynamic.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { join } from 'path' -import globby from 'globby' - -export async function createDynamicImporter (cwd: string) { - const assets = await globby('**/*.js', { cwd, absolute: false }) - const chunkInfo = {} - for (const asset of assets) { - const { id, ids, modules } = require(join(cwd, asset)) - if ((id || ids) && modules) { - chunkInfo[asset] = { id, ids, modules: Object.keys(modules) } - } - } - - return (syncImport, asyncImport) => genRequireDynamic(chunkInfo, syncImport, asyncImport) -} - -export function genRequireDynamic (chunkInfo, syncImport, asyncImport) { - return `\nconst _dynamic_chunks = ${JSON.stringify(chunkInfo, null, 2)}; -function requireDynamic (chunkId) { - const chunk = _dynamic_chunks[chunkId] - - if (!chunk) { - return ${syncImport} - } - - const promise = ${asyncImport} - - if (Array.isArray(chunk.modules)) { - const modules = {} - for (const id of chunk.modules) { - modules[id] = function (module, _exports, _require) { - module.exports = promise.then(chunk => { - const asyncModule = { exports: {}, require: _require } - chunk.modules[id](asyncModule, asyncModule.exports, asyncModule.require) - return asyncModule.exports - }) - } - } - chunk.modules = modules - } - - return chunk -};` -} diff --git a/packages/nitro/src/nuxt-deploy.ts b/packages/nitro/src/nuxt-deploy.ts index ec1807ae5a..748493c938 100644 --- a/packages/nitro/src/nuxt-deploy.ts +++ b/packages/nitro/src/nuxt-deploy.ts @@ -9,7 +9,6 @@ import gzipSize from 'gzip-size' import chalk from 'chalk' import { getRollupConfig } from './rollup.config' import { tryImport, hl, prettyPath } from './utils' -import { createDynamicImporter } from './dynamic' async function main () { const rootDir = resolve(process.cwd(), process.argv[2] || '.') @@ -20,8 +19,6 @@ async function main () { buildDir: '', targets: [], nuxt: 2, - importSync: "require('../server/' + chunkId)", - importAsync: "Promise.resolve(require('../server/' + chunkId))", 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, @@ -49,10 +46,6 @@ async function main () { await writeFile(htmlTemplateFileJS, htmlTemplateCompiled) consola.info('Generated', prettyPath(htmlTemplateFileJS)) - // Collect dynamic chunks - consola.info('Collecting dynamic chunks...') - const dynamicImporter = await createDynamicImporter(resolve(config.buildDir, 'dist/server')) - // Bundle for each target for (let target of config.targets) { if (typeof target === 'string') { @@ -69,8 +62,7 @@ async function main () { const ctx: any = defu( target, config, - tryImport(__dirname, `./targets/${target.target}`) || tryImport(config.rootDir, target.target), - { dynamicImporter } + tryImport(__dirname, `./targets/${target.target}`) || tryImport(config.rootDir, target.target) ) const hooks = new Hookable() diff --git a/packages/nitro/src/rollup.config.ts b/packages/nitro/src/rollup.config.ts index c5e3fac88b..687214a11e 100644 --- a/packages/nitro/src/rollup.config.ts +++ b/packages/nitro/src/rollup.config.ts @@ -9,6 +9,7 @@ import json from '@rollup/plugin-json' import replace from '@rollup/plugin-replace' import analyze from 'rollup-plugin-analyzer' import ts from 'rollup-plugin-ts' +import dynamicRequire from './dynamic-require' export type RollupConfig = InputOptions & { output: OutputOptions } @@ -66,13 +67,15 @@ export const getRollupConfig = (config) => { } })) - // Dynamic Importer - if (config.dynamicImporter) { - options.output.intro += config.dynamicImporter(config.importSync, config.importAsync) - } else { - options.output.intro += `const requireDynamic = (chunkId) => ${config.importSync}` - } - options.plugins.push(replace({ values: { 'require("./" +': 'requireDynamic(' }, delimiters: ['', ''] })) + // Dynamic Require Support + options.plugins.push(dynamicRequire({ + dir: path.resolve(config.buildDir, 'dist/server'), + globbyOptions: { + ignore: [ + 'server.js' + ] + } + })) // https://github.com/rollup/plugins/tree/master/packages/alias options.plugins.push(alias({