diff --git a/examples/ant-design-pro/config/config.ts b/examples/ant-design-pro/config/config.ts index bebee2cebe6a..217378fdd27d 100644 --- a/examples/ant-design-pro/config/config.ts +++ b/examples/ant-design-pro/config/config.ts @@ -335,4 +335,7 @@ export default defineConfig({ // type: 'none', // }, // exportStatic: {}, + codeSplitting: { + jsStrategy: 'granularChunks', + }, }); diff --git a/examples/max/.umirc.ts b/examples/max/.umirc.ts index 11d3e8deb73f..9c730a0d94a4 100644 --- a/examples/max/.umirc.ts +++ b/examples/max/.umirc.ts @@ -101,4 +101,7 @@ export default defineConfig({ // vite: {} // esmi: { cdnOrigin: 'https://npmcore-pre.alipay.com' }, // lowImport: {}, + codeSplitting: { + jsStrategy: 'granularChunks', + }, }); diff --git a/packages/preset-umi/src/commands/build.ts b/packages/preset-umi/src/commands/build.ts index a39244191c17..7e1876d8d3cf 100644 --- a/packages/preset-umi/src/commands/build.ts +++ b/packages/preset-umi/src/commands/build.ts @@ -170,18 +170,11 @@ umi build --clean styles: markupArgs.styles.concat( api.config.vite ? [] - : [ - ...(assetsMap['framework.css'] || []).map((src) => ({ src })), - ...(assetsMap['umi.css'] || []).map((src) => ({ src })), - ], + : [...(assetsMap['umi.css'] || []).map((src) => ({ src }))], ), scripts: (api.config.vite ? [] - : [ - // framework 先写死,后续考虑通过插件的方式注入 - ...(assetsMap['framework.js'] || []).map((src) => ({ src })), - ...(assetsMap['umi.js'] || []).map((src) => ({ src })), - ] + : [...(assetsMap['umi.js'] || []).map((src) => ({ src }))] ).concat(markupArgs.scripts), esmScript: !!opts.config.esm || vite, path: '/', diff --git a/packages/preset-umi/src/commands/dev/getAssetsMap.ts b/packages/preset-umi/src/commands/dev/getAssetsMap.ts index 7c7ea6f7a36b..b92b9f0f7f4b 100644 --- a/packages/preset-umi/src/commands/dev/getAssetsMap.ts +++ b/packages/preset-umi/src/commands/dev/getAssetsMap.ts @@ -2,10 +2,7 @@ const UMI_ASSETS_REG = { js: /^umi(\..+)?\.js$/, css: /^umi(\..+)?\.css$/, }; -const FRAMEWORK_ASSETS_REG = { - js: /^framework(\..+)?\.js$/, - css: /^framework(\..+)?\.css$/, -}; + const HOT_UPDATE = '.hot-update.'; export function getAssetsMap(opts: { stats: any; publicPath: string }) { @@ -20,16 +17,10 @@ export function getAssetsMap(opts: { stats: any; publicPath: string }) { if (UMI_ASSETS_REG.js.test(asset)) { ret['umi.js'] = [`${displayPublicPath}${asset}`]; } - if (FRAMEWORK_ASSETS_REG.js.test(asset)) { - ret['framework.js'] = [`${displayPublicPath}${asset}`]; - } } if (UMI_ASSETS_REG.css.test(asset)) { ret['umi.css'] = [`${displayPublicPath}${asset}`]; } - if (FRAMEWORK_ASSETS_REG.css.test(asset)) { - ret['framework.css'] = [`${displayPublicPath}${asset}`]; - } } return ret; } diff --git a/packages/preset-umi/src/features/codeSplitting/codeSplitting.ts b/packages/preset-umi/src/features/codeSplitting/codeSplitting.ts index 3a10c6ce8a7d..0e5f3c4d3357 100644 --- a/packages/preset-umi/src/features/codeSplitting/codeSplitting.ts +++ b/packages/preset-umi/src/features/codeSplitting/codeSplitting.ts @@ -141,10 +141,10 @@ export default (api: IApi) => { .replace(/=/g, '_'); return `shared-${cryptoName}`; }, - chunks: 'async', priority: 10, minChunks: 2, reuseExistingChunk: true, + chunks: 'async', }, }, }); diff --git a/packages/preset-umi/src/features/webpack/webpack.ts b/packages/preset-umi/src/features/webpack/webpack.ts new file mode 100644 index 000000000000..a97a7d73cd9b --- /dev/null +++ b/packages/preset-umi/src/features/webpack/webpack.ts @@ -0,0 +1,93 @@ +import type webpack from '@umijs/bundler-webpack/compiled/webpack'; +import { IApi } from '../../types'; + +export default (api: IApi) => { + api.describe({ + key: 'preset-umi:webpack', + enableBy: () => api.env === 'production', + }); + + // html 处理逻辑 + const assets: { js: string[]; css: string[]; [key: string]: string[] } = { + // Will contain all js and mjs files + js: [], + // Will contain all css files + css: [], + }; + + class HtmlWebpackPlugin { + apply(compiler: webpack.Compiler) { + compiler.hooks.emit.tapPromise( + 'UmiHtmlGeneration', + async (compilation) => { + const entryPointFiles = compilation.entrypoints + .get('umi')! + .getFiles(); + + // Extract paths to .js, .mjs and .css files from the current compilation + const entryPointPublicPathMap: Record = {}; + const extensionRegexp = /\.(css|js|mjs)(\?|$)/; + + const UMI_ASSETS_REG = { + js: /^umi(\..+)?\.js$/, + css: /^umi(\..+)?\.css$/, + }; + + entryPointFiles.forEach((entryPointPublicPath) => { + const extMatch = extensionRegexp.exec(entryPointPublicPath); + // Skip if the public path is not a .css, .mjs or .js file + if (!extMatch) { + return; + } + + if (entryPointPublicPath.includes('.hot-update')) { + return; + } + + // Skip if this file is already known + // (e.g. because of common chunk optimizations) + if (entryPointPublicPathMap[entryPointPublicPath]) { + return; + } + + // umi html 默认会注入 不做处理 + if ( + UMI_ASSETS_REG.js.test(entryPointPublicPath) || + UMI_ASSETS_REG.css.test(entryPointPublicPath) + ) { + return; + } + + entryPointPublicPathMap[entryPointPublicPath] = true; + // ext will contain .js or .css, because .mjs recognizes as .js + const ext = extMatch[1] === 'mjs' ? 'js' : extMatch[1]; + assets[ext].push(entryPointPublicPath); + }); + }, + ); + } + } + + api.modifyWebpackConfig((config) => { + // 处理 代码拆分时, 拆分的 非 入口文件, 自动注入到 html 文件中 + config.plugins?.push(new HtmlWebpackPlugin()); + return config; + }); + + api.addHTMLStyles(() => { + const { publicPath } = api.config; + const displayPublicPath = publicPath === 'auto' ? '/' : publicPath; + return assets.css.map((css) => { + return `${displayPublicPath}${css}`; + }); + }); + + api.addHTMLHeadScripts(() => { + const { publicPath } = api.config; + const displayPublicPath = publicPath === 'auto' ? '/' : publicPath; + + return assets.js.map((js) => { + return `${displayPublicPath}${js}`; + }); + }); +}; diff --git a/packages/preset-umi/src/index.ts b/packages/preset-umi/src/index.ts index 86336f57fd57..717cc8b8e5da 100644 --- a/packages/preset-umi/src/index.ts +++ b/packages/preset-umi/src/index.ts @@ -41,6 +41,7 @@ export default () => { require.resolve('./features/clickToComponent/clickToComponent'), require.resolve('./features/legacy/legacy'), require.resolve('./features/classPropertiesLoose/classPropertiesLoose'), + require.resolve('./features/webpack/webpack'), // commands require.resolve('./commands/build'),