diff --git a/docs/plugin/develop.md b/docs/plugin/develop.md index f68d60e77068..b765d802cfbf 100644 --- a/docs/plugin/develop.md +++ b/docs/plugin/develop.md @@ -402,6 +402,10 @@ api.addHTMLScript({ Add a script to the HTML head. +### modifyHTMLChunks + +Modify chunks in HTML. + ### modifyHTMLWithAST Modify the HTML, based on cheerio. diff --git a/docs/zh/plugin/develop.md b/docs/zh/plugin/develop.md index 92e816513600..f414ceee764e 100644 --- a/docs/zh/plugin/develop.md +++ b/docs/zh/plugin/develop.md @@ -403,6 +403,10 @@ api.addHTMLScript({ 在 HTML 头部添加脚本。 +### modifyHTMLChunks + +修改 chunks 。 + ### modifyHTMLWithAST 修改 HTML,基于 cheerio 。 diff --git a/packages/umi-build-dev/src/PluginAPI.js b/packages/umi-build-dev/src/PluginAPI.js index da472697c9fd..bed6f22b520b 100644 --- a/packages/umi-build-dev/src/PluginAPI.js +++ b/packages/umi-build-dev/src/PluginAPI.js @@ -93,6 +93,7 @@ export default class PluginAPI { 'addHTMLScript', 'addHTMLStyle', 'addHTMLHeadScript', + 'modifyHTMLChunks', 'onGenerateFiles', 'onHTMLRebuild', 'modifyDefaultConfig', diff --git a/packages/umi-build-dev/src/html/HTMLGenerator.js b/packages/umi-build-dev/src/html/HTMLGenerator.js index 51c459b4e376..cce831ede259 100644 --- a/packages/umi-build-dev/src/html/HTMLGenerator.js +++ b/packages/umi-build-dev/src/html/HTMLGenerator.js @@ -1,5 +1,5 @@ import assert from 'assert'; -import { join, relative } from 'path'; +import { join, relative, extname } from 'path'; import { existsSync, readFileSync } from 'fs'; import isPlainObject from 'is-plain-object'; import ejs from 'ejs'; @@ -188,18 +188,16 @@ export default class HTMLGenerator { } getHashedFileName(filename) { - const isProduction = this.env === 'production'; - if (isProduction) { + // css is optional + if (extname(filename) === '.js') { assert( this.chunksMap[filename], `file ${filename} don't exists in chunksMap ${JSON.stringify( this.chunksMap, )}`, ); - return this.chunksMap[filename]; - } else { - return filename; } + return this.chunksMap[filename]; } getContent(route) { @@ -246,6 +244,9 @@ export default class HTMLGenerator { let scripts = []; let styles = []; let headScripts = []; + let chunks = ['umi']; + + if (this.modifyChunks) chunks = this.modifyChunks(chunks); let routerBaseStr = JSON.stringify(this.config.base || '/'); const publicPath = this.publicPath || '/'; @@ -273,8 +274,14 @@ export default class HTMLGenerator { ...(setPublicPath ? [`window.publicPath = ${publicPathStr};`] : []), ].join('\n'), }); - scripts.push({ - src: `<%= pathToPublicPath %>${this.getHashedFileName('umi.js')}`, + + chunks.forEach(chunk => { + const hashedFileName = this.getHashedFileName(`${chunk}.js`); + if (hashedFileName) { + scripts.push({ + src: `<%= pathToPublicPath %>${hashedFileName}`, + }); + } }); if (this.modifyMetas) metas = this.modifyMetas(metas); @@ -286,9 +293,14 @@ export default class HTMLGenerator { if (this.env === 'development' || this.chunksMap['umi.css']) { // umi.css should be the last one stylesheet - links.push({ - rel: 'stylesheet', - href: `<%= pathToPublicPath %>${this.getHashedFileName('umi.css')}`, + chunks.forEach(chunk => { + const hashedFileName = this.getHashedFileName(`${chunk}.css`); + if (hashedFileName) { + links.push({ + rel: 'stylesheet', + href: `<%= pathToPublicPath %>${hashedFileName}`, + }); + } }); } @@ -322,7 +334,9 @@ ${scripts.length ? this.getScriptsContent(scripts) : ''} exportStatic && exportStatic.dynamicRoot ? relPathToPublicPath : publicPath; - html = html.replace(/<%= pathToPublicPath %>/g, pathToPublicPath); + html = html + .replace(/<%= pathToPublicPath %>/g, pathToPublicPath) + .replace(/<%= PUBLIC_PATH %>/g, pathToPublicPath); if (this.modifyHTML) { html = this.modifyHTML(html, { route }); diff --git a/packages/umi-build-dev/src/plugins/commands/dev/createRouteMiddleware.js b/packages/umi-build-dev/src/plugins/commands/dev/createRouteMiddleware.js index 8c10925b8a8d..c25d29039b44 100644 --- a/packages/umi-build-dev/src/plugins/commands/dev/createRouteMiddleware.js +++ b/packages/umi-build-dev/src/plugins/commands/dev/createRouteMiddleware.js @@ -1,4 +1,5 @@ import getHtmlGenerator from '../getHtmlGenerator'; +import chunksToMap from '../build/chunksToMap'; export default function createRouteMiddleware(service) { return (req, res) => { @@ -8,7 +9,10 @@ export default function createRouteMiddleware(service) { res.setHeader('Content-Type', 'text/json'); res.send(JSON.stringify(service.routes)); } else { - const htmlGenerator = getHtmlGenerator(service); + const chunksMap = chunksToMap(service.__chunks); + const htmlGenerator = getHtmlGenerator(service, { + chunksMap, + }); const content = htmlGenerator.getMatchedContent(path); res.setHeader('Content-Type', 'text/html'); res.send(content); diff --git a/packages/umi-build-dev/src/plugins/commands/dev/index.js b/packages/umi-build-dev/src/plugins/commands/dev/index.js index e4211e51db05..85abcd94fb52 100644 --- a/packages/umi-build-dev/src/plugins/commands/dev/index.js +++ b/packages/umi-build-dev/src/plugins/commands/dev/index.js @@ -105,6 +105,7 @@ export default function(api) { startWatch(); }, onCompileDone({ isFirstCompile, stats }) { + service.__chunks = stats.compilation.chunks; service.applyPlugins('onDevCompileDone', { args: { isFirstCompile, diff --git a/packages/umi-build-dev/src/plugins/commands/getHtmlGenerator.js b/packages/umi-build-dev/src/plugins/commands/getHtmlGenerator.js index 99a4e2a844c6..ca7a6f4d2551 100644 --- a/packages/umi-build-dev/src/plugins/commands/getHtmlGenerator.js +++ b/packages/umi-build-dev/src/plugins/commands/getHtmlGenerator.js @@ -22,6 +22,11 @@ export default (service, opts = {}) => { modifyPublicPathStr(str) { return str; }, + modifyChunks(memo) { + return service.applyPlugins('modifyHTMLChunks', { + initialValue: memo, + }); + }, modifyMetas(memo) { return service.applyPlugins('addHTMLMeta', { initialValue: memo, diff --git a/packages/umi-plugin-react/src/index.js b/packages/umi-plugin-react/src/index.js index bf75aed6a8c7..d6d37378c283 100644 --- a/packages/umi-plugin-react/src/index.js +++ b/packages/umi-plugin-react/src/index.js @@ -47,6 +47,13 @@ export default function(api, option) { hardSource: () => require('./plugins/hardSource').default, pwa: () => require('./plugins/pwa').default, + // html tags + chunks: () => require('./plugins/chunks').default, + scripts: () => require('./plugins/scripts').default, + headScripts: () => require('./plugins/headScripts').default, + links: () => require('./plugins/links').default, + metas: () => require('./plugins/metas').default, + // misc dva: () => require('./plugins/dva').default, locale: () => require('./plugins/locale').default, diff --git a/packages/umi-plugin-react/src/plugins/chunks.js b/packages/umi-plugin-react/src/plugins/chunks.js new file mode 100644 index 000000000000..acb3dee8cdba --- /dev/null +++ b/packages/umi-plugin-react/src/plugins/chunks.js @@ -0,0 +1,11 @@ +export default function(api, option) { + api.onOptionChange(newOption => { + option = newOption; + api.rebuildHTML(); + api.refreshBrowser(); + }); + + api.modifyHTMLChunks(() => { + return option; + }); +} diff --git a/packages/umi-plugin-react/src/plugins/headScripts.js b/packages/umi-plugin-react/src/plugins/headScripts.js new file mode 100644 index 000000000000..d715b67b3028 --- /dev/null +++ b/packages/umi-plugin-react/src/plugins/headScripts.js @@ -0,0 +1,11 @@ +export default function(api, option) { + api.onOptionChange(newOption => { + option = newOption; + api.rebuildHTML(); + api.refreshBrowser(); + }); + + api.addHTMLHeadScript(() => { + return option; + }); +} diff --git a/packages/umi-plugin-react/src/plugins/links.js b/packages/umi-plugin-react/src/plugins/links.js new file mode 100644 index 000000000000..72a302562f02 --- /dev/null +++ b/packages/umi-plugin-react/src/plugins/links.js @@ -0,0 +1,11 @@ +export default function(api, option) { + api.onOptionChange(newOption => { + option = newOption; + api.rebuildHTML(); + api.refreshBrowser(); + }); + + api.addHTMLLink(() => { + return option; + }); +} diff --git a/packages/umi-plugin-react/src/plugins/metas.js b/packages/umi-plugin-react/src/plugins/metas.js new file mode 100644 index 000000000000..866a7a916ac8 --- /dev/null +++ b/packages/umi-plugin-react/src/plugins/metas.js @@ -0,0 +1,11 @@ +export default function(api, option) { + api.onOptionChange(newOption => { + option = newOption; + api.rebuildHTML(); + api.refreshBrowser(); + }); + + api.addHTMLMeta(() => { + return option; + }); +} diff --git a/packages/umi-plugin-react/src/plugins/mobile/fastClick.js b/packages/umi-plugin-react/src/plugins/mobile/fastClick.js deleted file mode 100644 index 157c146d86b5..000000000000 --- a/packages/umi-plugin-react/src/plugins/mobile/fastClick.js +++ /dev/null @@ -1 +0,0 @@ -export default from '../fastClick'; diff --git a/packages/umi-plugin-react/src/plugins/mobile/hd.js b/packages/umi-plugin-react/src/plugins/mobile/hd.js deleted file mode 100644 index d4b2ce49bf7e..000000000000 --- a/packages/umi-plugin-react/src/plugins/mobile/hd.js +++ /dev/null @@ -1 +0,0 @@ -export default from '../hd'; diff --git a/packages/umi-plugin-react/src/plugins/scripts.js b/packages/umi-plugin-react/src/plugins/scripts.js new file mode 100644 index 000000000000..abfdf7da2442 --- /dev/null +++ b/packages/umi-plugin-react/src/plugins/scripts.js @@ -0,0 +1,11 @@ +export default function(api, option) { + api.onOptionChange(newOption => { + option = newOption; + api.rebuildHTML(); + api.refreshBrowser(); + }); + + api.addHTMLScript(() => { + return option; + }); +} diff --git a/packages/umi-plugin-react/test/chunks/.umirc.js b/packages/umi-plugin-react/test/chunks/.umirc.js new file mode 100644 index 000000000000..ec10e97777f0 --- /dev/null +++ b/packages/umi-plugin-react/test/chunks/.umirc.js @@ -0,0 +1,30 @@ +export default { + plugins: [ + [ + '../../lib', + { + dynamicImport: { + webpackChunkName: true, + }, + chunks: ['vendors', 'umi'], + }, + ], + ], + chainWebpack(config) { + config.optimization.splitChunks({ + cacheGroups: { + vendors: { + name: 'vendors', + chunks: 'all', + test: /[\\/]node_modules[\\/](react|react-dom|react-router|react-router-dom)/, + }, + commons: { + name: 'commons', + chunks: 'async', + minChunks: 2, + minSize: 0, + }, + }, + }); + }, +}; diff --git a/packages/umi-plugin-react/test/chunks/a.js b/packages/umi-plugin-react/test/chunks/a.js new file mode 100644 index 000000000000..ba5d0e813943 --- /dev/null +++ b/packages/umi-plugin-react/test/chunks/a.js @@ -0,0 +1 @@ +console.log('module a'); diff --git a/packages/umi-plugin-react/test/chunks/package.json b/packages/umi-plugin-react/test/chunks/package.json new file mode 100644 index 000000000000..9e26dfeeb6e6 --- /dev/null +++ b/packages/umi-plugin-react/test/chunks/package.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/umi-plugin-react/test/chunks/pages/index.css b/packages/umi-plugin-react/test/chunks/pages/index.css new file mode 100644 index 000000000000..a4b84e2ef64c --- /dev/null +++ b/packages/umi-plugin-react/test/chunks/pages/index.css @@ -0,0 +1,4 @@ + +.normal { + background: #95F279; +} diff --git a/packages/umi-plugin-react/test/chunks/pages/index.js b/packages/umi-plugin-react/test/chunks/pages/index.js new file mode 100755 index 000000000000..efa3b266b682 --- /dev/null +++ b/packages/umi-plugin-react/test/chunks/pages/index.js @@ -0,0 +1,10 @@ +import styles from './index.css'; +import '../a'; + +export default function() { + return ( +