diff --git a/.changeset/legal-lines-strive.md b/.changeset/legal-lines-strive.md new file mode 100644 index 0000000000..2375686c99 --- /dev/null +++ b/.changeset/legal-lines-strive.md @@ -0,0 +1,7 @@ +--- +"@lynx-js/template-webpack-plugin": patch +--- + +Avoid generating lazy bundles when there are no chunk name. + +E.g.: using `import.meta.webpackContext`. diff --git a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md index cca9dfd4e6..f24e3d6820 100644 --- a/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md +++ b/packages/webpack/template-webpack-plugin/etc/template-webpack-plugin.api.md @@ -130,7 +130,7 @@ export interface TemplateHooks { outputName: string; }>; // @alpha - asyncChunkName: SyncWaterfallHook; + asyncChunkName: SyncWaterfallHook; // @alpha beforeEmit: AsyncSeriesWaterfallHook<{ finalEncodeOptions: EncodeOptions; diff --git a/packages/webpack/template-webpack-plugin/src/LynxAsyncChunksRuntimeModule.ts b/packages/webpack/template-webpack-plugin/src/LynxAsyncChunksRuntimeModule.ts index fab59186a2..37329127d7 100644 --- a/packages/webpack/template-webpack-plugin/src/LynxAsyncChunksRuntimeModule.ts +++ b/packages/webpack/template-webpack-plugin/src/LynxAsyncChunksRuntimeModule.ts @@ -7,7 +7,7 @@ import type { RuntimeModule } from 'webpack'; import { RuntimeGlobals } from '@lynx-js/webpack-runtime-globals'; type LynxAsyncChunksRuntimeModule = new( - getChunkName: (chunkName: string | null | undefined) => string, + getChunkName: (chunkName: string) => string, ) => RuntimeModule; export function createLynxAsyncChunksRuntimeModule( @@ -15,7 +15,7 @@ export function createLynxAsyncChunksRuntimeModule( ): LynxAsyncChunksRuntimeModule { return class LynxAsyncChunksRuntimeModule extends webpack.RuntimeModule { constructor( - public getChunkName: (chunkName: string | null | undefined) => string, + public getChunkName: (chunkName: string) => string, ) { super('Lynx async chunks', webpack.RuntimeModule.STAGE_ATTACH); } @@ -26,9 +26,10 @@ export function createLynxAsyncChunksRuntimeModule( return `// lynx async chunks ids ${RuntimeGlobals.lynxAsyncChunkIds} = {${ - Array.from(chunk.getAllAsyncChunks()).map( - c => { - const filename = this.getChunkName(c.name); + Array.from(chunk.getAllAsyncChunks()) + .filter(c => c.name !== null && c.name !== undefined) + .map(c => { + const filename = this.getChunkName(c.name!); // Modified from https://github.com/webpack/webpack/blob/11449f02175f055a4540d76aa4478958c4cb297e/lib/runtime/GetChunkFilenameRuntimeModule.js#L154-L157 const chunkPath = compilation.getPath(filename, { @@ -40,9 +41,9 @@ ${RuntimeGlobals.lynxAsyncChunkIds} = {${ }); return [c.id, chunkPath]; - }, + }) // Do not use `JSON.stringify` on `chunkPath`, it may contains `+` which will be treated as string concatenation. - ).map(([id, path]) => `${JSON.stringify(id)}: "${path}"`).join(',\n') + .map(([id, path]) => `${JSON.stringify(id)}: "${path}"`).join(',\n') }}`; } }; diff --git a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts index 98d178d48b..680666af4b 100644 --- a/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts +++ b/packages/webpack/template-webpack-plugin/src/LynxTemplatePlugin.ts @@ -75,7 +75,7 @@ export interface TemplateHooks { * * @alpha */ - asyncChunkName: SyncWaterfallHook; + asyncChunkName: SyncWaterfallHook; /** * Called before the encode process. Can be used to modify the encode options. @@ -549,7 +549,7 @@ class LynxTemplatePluginImpl { compilation.addRuntimeModule( chunk, new LynxAsyncChunksRuntimeModule((chunkName) => { - const filename = hooks.asyncChunkName.call(chunkName)!; + const filename = hooks.asyncChunkName.call(chunkName); return this.#getAsyncFilenameTemplate(filename); }), @@ -637,8 +637,9 @@ class LynxTemplatePluginImpl { asyncChunkGroups = groupBy( compilation.chunkGroups - .filter(cg => !cg.isInitial()), - cg => hooks.asyncChunkName.call(cg.name)!, + .filter(cg => !cg.isInitial()) + .filter(cg => cg.name !== null && cg.name !== undefined), + cg => hooks.asyncChunkName.call(cg.name!), ); LynxTemplatePluginImpl.#asyncChunkGroups.set(compilation, asyncChunkGroups); @@ -676,8 +677,8 @@ class LynxTemplatePluginImpl { const chunkNames = // We use the chunk name(provided by `webpackChunkName`) as filename chunkGroups - .map(cg => hooks.asyncChunkName.call(cg.name)) - .filter(chunkName => chunkName !== undefined); + .filter(cg => cg.name !== null && cg.name !== undefined) + .map(cg => hooks.asyncChunkName.call(cg.name!)); const filename = Array.from(new Set(chunkNames)).join('_'); diff --git a/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/a.json b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/a.json new file mode 100644 index 0000000000..44d21f1fa7 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/a.json @@ -0,0 +1,3 @@ +{ + "name": "a" +} diff --git a/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/b.json b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/b.json new file mode 100644 index 0000000000..bbe7ab805e --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/b.json @@ -0,0 +1,3 @@ +{ + "name": "b" +} diff --git a/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/index.js b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/index.js new file mode 100644 index 0000000000..335de3eafb --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/index.js @@ -0,0 +1,24 @@ +/* +// Copyright 2024 The Lynx Authors. All rights reserved. +// Licensed under the Apache License Version 2.0 that can be found in the +// LICENSE file in the root directory of this source tree. +*/ +/// + +import { existsSync } from 'node:fs'; +import { resolve } from 'node:path'; + +it('should have correct chunk content', async () => { + const request = async (name) => await import(`./${name}.json`); + const a = await request('a'); + const b = await request('b'); + expect(a.default.name).toBe('a'); + expect(b.default.name).toBe('b'); + + expect(__webpack_require__.lynx_aci).toBeUndefined(); +}); + +it('should not generate bundle for context', () => { + const tasmJSONPath = resolve(__dirname, '.rspeedy/async/a/tasm.json'); + expect(existsSync(tasmJSONPath)).toBeFalsy(); +}); diff --git a/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/rspack.config.js b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/rspack.config.js new file mode 100644 index 0000000000..e5ff6451a7 --- /dev/null +++ b/packages/webpack/template-webpack-plugin/test/cases/code-splitting/context/rspack.config.js @@ -0,0 +1,31 @@ +import { LynxEncodePlugin, LynxTemplatePlugin } from '../../../../src'; + +/** @type {import('@rspack/core').Configuration} */ +export default { + devtool: false, + mode: 'development', + plugins: [ + new LynxEncodePlugin(), + new LynxTemplatePlugin({ + ...LynxTemplatePlugin.defaultOptions, + intermediate: '.rspeedy/main', + }), + /** + * @param {import('@rspack/core').Compiler} compiler - Rspack Compiler + */ + (compiler) => { + compiler.hooks.thisCompilation.tap('test', (compilation) => { + const hooks = LynxTemplatePlugin.getLynxTemplatePluginHooks( + compilation, + ); + hooks.asyncChunkName.tap( + 'test', + chunkName => + chunkName + .replace(':main-thread', '') + .replace(':background', ''), + ); + }); + }, + ], +}; diff --git a/packages/webpack/template-webpack-plugin/test/cases/runtime-module/async-chunk/index.js b/packages/webpack/template-webpack-plugin/test/cases/runtime-module/async-chunk/index.js index 87040290ac..edb6daa991 100644 --- a/packages/webpack/template-webpack-plugin/test/cases/runtime-module/async-chunk/index.js +++ b/packages/webpack/template-webpack-plugin/test/cases/runtime-module/async-chunk/index.js @@ -1,6 +1,9 @@ /// -import('./dynamic.js'); +import( + /* webpackChunkName: 'dynamic' */ + './dynamic.js' +); it('should have changed bundle', () => { expect(Object.values(__webpack_require__['lynx_aci'])).toStrictEqual([