1 | const path = require('path')
|
2 | const fs = require('fs')
|
3 | const merge = require('lodash.merge')
|
4 |
|
5 | exports.name = 'builtin:config-html'
|
6 |
|
7 | exports.apply = api => {
|
8 | api.hook('createWebpackChain', config => {
|
9 |
|
10 |
|
11 | if (api.config.output.format === 'cjs') return
|
12 |
|
13 | const HtmlPlugin = require('html-webpack-plugin')
|
14 | HtmlPlugin.__expression = `require('html-webpack-plugin')`
|
15 |
|
16 |
|
17 | if (api.mode === 'production' && api.config.output.format === 'iife') {
|
18 | config.optimization.splitChunks({
|
19 | cacheGroups: {
|
20 | vendors: {
|
21 | name: `chunk-vendors`,
|
22 | test: /[\\/]node_modules[\\/]/,
|
23 | priority: -10,
|
24 | chunks: 'initial'
|
25 | },
|
26 | common: {
|
27 | name: `chunk-common`,
|
28 | minChunks: 2,
|
29 | priority: -20,
|
30 | chunks: 'initial',
|
31 | reuseExistingChunk: true
|
32 | }
|
33 | }
|
34 | })
|
35 |
|
36 |
|
37 | config.optimization.runtimeChunk(true)
|
38 | }
|
39 |
|
40 | const DEFAULT_TEMPLATE = path.join(
|
41 | __dirname,
|
42 | '../webpack/default-template.html'
|
43 | )
|
44 |
|
45 | const getDefaultTemplate = () => {
|
46 | if (!api.config.publicFolder) {
|
47 | return DEFAULT_TEMPLATE
|
48 | }
|
49 |
|
50 | const userTemplatePath = api.resolveCwd(
|
51 | api.config.publicFolder,
|
52 | 'index.html'
|
53 | )
|
54 | return (
|
55 | api.config.defaultHtmlTemplate ||
|
56 | (fs.existsSync(userTemplatePath) ? userTemplatePath : DEFAULT_TEMPLATE)
|
57 | )
|
58 | }
|
59 |
|
60 | const defaultHtmlOpts = {
|
61 | title: api.pkg.data.productName || api.pkg.data.name || 'Poi App',
|
62 | template: getDefaultTemplate(),
|
63 | templateParameters: templateParametersGenerator({
|
64 | pkg: api.pkg.data,
|
65 | envs: api.webpackUtils.envs,
|
66 | constants: api.webpackUtils.constants
|
67 | }),
|
68 | filename: 'index.html',
|
69 | minify: api.isProd
|
70 | ? {
|
71 | removeComments: true,
|
72 | collapseWhitespace: true,
|
73 | removeRedundantAttributes: true,
|
74 | useShortDoctype: true,
|
75 | removeEmptyAttributes: true,
|
76 | removeStyleLinkTypeAttributes: true,
|
77 | keepClosingSlash: true,
|
78 | minifyJS: true,
|
79 | minifyCSS: true,
|
80 | minifyURLs: true
|
81 | }
|
82 | : undefined
|
83 | }
|
84 |
|
85 | const { pages } = api.config
|
86 | const { html } = api.config.output
|
87 |
|
88 | if (html !== false) {
|
89 | if (pages) {
|
90 | for (const entryName of Object.keys(pages)) {
|
91 | const page = merge(
|
92 | {},
|
93 | defaultHtmlOpts,
|
94 | {
|
95 | filename: `${entryName}.html`,
|
96 | chunks: ['chunk-vendors', 'chunk-common', entryName]
|
97 | },
|
98 | typeof pages[entryName] === 'string' ? {} : pages[entryName]
|
99 | )
|
100 | page.template = api.resolveCwd(page.template)
|
101 | config.plugin(`html-page-${entryName}`).use(HtmlPlugin, [page])
|
102 | }
|
103 | } else {
|
104 | const page = merge({}, defaultHtmlOpts, html)
|
105 | page.template = api.resolveCwd(page.template)
|
106 | config.plugin('html').use(HtmlPlugin, [page])
|
107 | }
|
108 |
|
109 | config
|
110 | .plugin('inline-runtime-chunk')
|
111 | .use(require('@poi/dev-utils/InlineChunkHtmlPlugin'), [
|
112 | require('html-webpack-plugin'),
|
113 | [/runtime~.+[.]js/]
|
114 | ])
|
115 | }
|
116 | })
|
117 | }
|
118 |
|
119 | function templateParametersGenerator(data) {
|
120 | const { htmlTagObjectToString } = require('html-webpack-plugin/lib/html-tags')
|
121 |
|
122 | return (compilation, assets, assetTags, options) => {
|
123 | const { xhtml } = options
|
124 | assetTags.headTags.toString = function() {
|
125 | return this.map(assetTagObject =>
|
126 | htmlTagObjectToString(assetTagObject, xhtml)
|
127 | ).join('')
|
128 | }
|
129 | assetTags.bodyTags.toString = function() {
|
130 | return this.map(assetTagObject =>
|
131 | htmlTagObjectToString(assetTagObject, xhtml)
|
132 | ).join('')
|
133 | }
|
134 | return Object.assign(
|
135 | {
|
136 | compilation,
|
137 | webpackConfig: compilation.options,
|
138 | htmlWebpackPlugin: {
|
139 | tags: assetTags,
|
140 | files: assets,
|
141 | options
|
142 | },
|
143 | html: options
|
144 | },
|
145 | data
|
146 | )
|
147 | }
|
148 | }
|