1 | 'use strict'
|
2 |
|
3 | const path = require('path')
|
4 | const fs = require('fs')
|
5 | const webpack = require('webpack')
|
6 | const merge = require('webpack-merge')
|
7 | const chalk = require('chalk')
|
8 | const CopyWebpackPlugin = require('copy-webpack-plugin-hash')
|
9 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
10 | const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin')
|
11 | const HtmlWebpackPlugin = require('sina-html-webpack-plugin')
|
12 | const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
13 | const moduleDependency = require('sinamfe-webpack-module_dependency')
|
14 | const { HybridCommonPlugin } = require('../libs/hybrid')
|
15 | const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
|
16 | const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin')
|
17 | const ZenJsPlugin = require('../libs/ZenJsPlugin')
|
18 |
|
19 | const config = require('../config')
|
20 | const { banner, rootPath, getChunks, isObject } = require('../libs/utils')
|
21 |
|
22 | const maraConf = require(config.paths.marauder)
|
23 | const shouldUseSourceMap = !!maraConf.sourceMap
|
24 | const isHybridMode = config.build.env.raw['jsbridgeBuildType'] === 'app'
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
31 |
|
32 | module.exports = function({ entry, cmd }) {
|
33 | const distPageDir = `${config.paths.dist}/${entry}`
|
34 | const baseWebpackConfig = require('./webpack.base.conf')(entry, 'build')
|
35 | const hasHtml = fs.existsSync(`${config.paths.page}/${entry}/index.html`)
|
36 | const chunksEntry = getChunks(`src/view/${entry}/index.*.js`)
|
37 | const debugLabel = config.debug ? '.debug' : ''
|
38 | const shouldUseZenJs = config.compiler.zenJs && !isHybridMode
|
39 |
|
40 |
|
41 | const webpackConfig = merge(baseWebpackConfig, {
|
42 |
|
43 | bail: true,
|
44 | devtool: shouldUseSourceMap ? 'source-map' : false,
|
45 | entry: chunksEntry,
|
46 | output: {
|
47 | path: distPageDir,
|
48 | publicPath: config.build.assetsPublicPath,
|
49 | filename: maraConf.hash
|
50 | ? `static/js/[name].[chunkhash:8]${debugLabel}.js`
|
51 | : `static/js/[name]${debugLabel || '.min'}.js`,
|
52 | chunkFilename: maraConf.chunkHash
|
53 | ? `static/js/[name].[chunkhash:8].async${debugLabel}.js`
|
54 | : `static/js/[name].async${debugLabel}.js`
|
55 | },
|
56 | plugins: [
|
57 | new InterpolateHtmlPlugin(config.build.env.raw),
|
58 | new webpack.DefinePlugin(config.build.env.stringified),
|
59 |
|
60 |
|
61 | new webpack.optimize.ModuleConcatenationPlugin(),
|
62 | config.debug && new webpack.NamedModulesPlugin(),
|
63 |
|
64 | new UglifyJsPlugin({
|
65 | uglifyOptions: {
|
66 |
|
67 | ecma: 5,
|
68 | compress: {
|
69 | warnings: false,
|
70 |
|
71 |
|
72 |
|
73 |
|
74 | comparisons: false,
|
75 | drop_console: !config.debug && config.compiler.dropConsole,
|
76 | join_vars: !config.debug
|
77 | },
|
78 | mangle: config.debug
|
79 | ? false
|
80 | : {
|
81 | safari10: true
|
82 | },
|
83 | keep_fnames: config.debug,
|
84 | output: {
|
85 | comments: false,
|
86 |
|
87 |
|
88 | ascii_only: true,
|
89 | comments: config.debug && /(\sMODULE)|(^\s\d+\s$)/,
|
90 | beautify: config.debug
|
91 | }
|
92 | },
|
93 |
|
94 |
|
95 | parallel: true,
|
96 |
|
97 | cache: true,
|
98 | sourceMap: shouldUseSourceMap
|
99 | }),
|
100 | new ExtractTextPlugin({
|
101 | filename: maraConf.hash
|
102 | ? 'static/css/[name].[contenthash:8].css'
|
103 | : 'static/css/[name].min.css'
|
104 | }),
|
105 |
|
106 |
|
107 | new HybridCommonPlugin(),
|
108 | new OptimizeCssAssetsPlugin({
|
109 |
|
110 |
|
111 |
|
112 | cssProcessor: require('cssnano'),
|
113 | cssProcessorOptions: Object.assign(
|
114 |
|
115 | shouldUseSourceMap
|
116 | ? {
|
117 | map: { inline: false }
|
118 | }
|
119 | : {}
|
120 | ),
|
121 | canPrint: false
|
122 | }),
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 | new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
|
129 | hasHtml &&
|
130 | new HtmlWebpackPlugin({
|
131 |
|
132 | filename: rootPath(`dist/${entry}/index.html`),
|
133 |
|
134 | template: `${config.paths.page}/${entry}/index.html`,
|
135 | minify: false,
|
136 |
|
137 | inject: true,
|
138 |
|
139 | chunksSortMode(a, b) {
|
140 | const chunkNames = Object.keys(chunksEntry).sort()
|
141 | const order = ['common', entry].concat(chunkNames)
|
142 |
|
143 | return order.indexOf(a.names[0]) - order.indexOf(b.names[0])
|
144 | },
|
145 | collapseWhitespace: true,
|
146 | removeRedundantAttributes: true,
|
147 | useShortDoctype: true,
|
148 | removeEmptyAttributes: true,
|
149 | removeStyleLinkTypeAttributes: true,
|
150 | keepClosingSlash: true
|
151 | }),
|
152 | hasHtml && shouldUseZenJs && new ZenJsPlugin(),
|
153 |
|
154 | new moduleDependency({
|
155 | emitError: config.compiler.checkDuplicatePackage !== false
|
156 | }),
|
157 | new DuplicatePackageCheckerPlugin({
|
158 |
|
159 | verbose: true,
|
160 | showHelp: false,
|
161 |
|
162 | emitError: config.compiler.checkDuplicatePackage,
|
163 |
|
164 | strict: true
|
165 | }),
|
166 | new webpack.BannerPlugin({
|
167 | banner: banner(),
|
168 | entryOnly: false
|
169 | }),
|
170 | ...copyPublicFiles(entry, distPageDir)
|
171 | ].filter(Boolean)
|
172 | })
|
173 |
|
174 |
|
175 | if (maraConf.prerender) {
|
176 | const PrerenderSPAPlugin = require('prerender-html-plugin')
|
177 | const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
|
178 |
|
179 | new PrerenderSPAPlugin({
|
180 |
|
181 |
|
182 | entry: `${entry}`,
|
183 |
|
184 | staticDir: path.join(rootPath(`dist`), `${entry}`),
|
185 |
|
186 | outputDir: path.join(rootPath(`dist`), `${entry}`),
|
187 |
|
188 |
|
189 | routes: ['/'],
|
190 |
|
191 |
|
192 | renderer: new Renderer({
|
193 | inject: {
|
194 | foo: 'bar'
|
195 | },
|
196 | headless: false,
|
197 |
|
198 | renderAfterDocumentEvent: 'render-event'
|
199 | })
|
200 | })
|
201 | }
|
202 |
|
203 | if (maraConf.ensurels) {
|
204 | const ensure_ls = require('sinamfe-marauder-ensure-ls')
|
205 | webpackConfig.plugins.push(new ensure_ls())
|
206 | }
|
207 |
|
208 | const vendorConf = maraConf.vendor || []
|
209 | if (Object.keys(vendorConf).length) {
|
210 | if (isObject(vendorConf) && !vendorConf.libs) {
|
211 | console.log(
|
212 | chalk.yellow(
|
213 | 'Build skip, vendor.libs is undefined. Please check marauder.config.js'
|
214 | )
|
215 | )
|
216 | process.exit(0)
|
217 | }
|
218 |
|
219 | let manifest = ''
|
220 |
|
221 | const namespace = maraConf.vendor.name ? `${maraConf.vendor.name}_` : ''
|
222 |
|
223 | try {
|
224 | manifest = require(`${config.paths.dll}/${namespace}manifest.json`)
|
225 | } catch (err) {
|
226 | console.log(
|
227 | chalk.yellow(
|
228 | `dll/${namespace}manifest.json 未生成,请执行 npm run dll\n`
|
229 | )
|
230 | )
|
231 | process.exit(1)
|
232 | }
|
233 |
|
234 | webpackConfig.plugins.push(
|
235 | new webpack.DllReferencePlugin({
|
236 | manifest: manifest
|
237 | })
|
238 | )
|
239 | }
|
240 |
|
241 |
|
242 | if (config.build.bundleAnalyzerReport) {
|
243 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
244 | .BundleAnalyzerPlugin
|
245 | webpackConfig.plugins.push(new BundleAnalyzerPlugin())
|
246 | }
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | if (maraConf.zip === true || maraConf.hybrid) {
|
258 | const ZipPlugin = require('zip-webpack-plugin')
|
259 | webpackConfig.plugins.push(
|
260 | new ZipPlugin({
|
261 |
|
262 |
|
263 | filename: entry,
|
264 |
|
265 |
|
266 |
|
267 | extension: maraConf.hybrid ? 'php' : 'zip',
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 | exclude: maraConf.debug
|
275 | ? [
|
276 | /__MACOSX$/,
|
277 | /.DS_Store$/,
|
278 | /dependencyGraph.json$/,
|
279 | /debug.css$/,
|
280 | /build.json$/,
|
281 | /js.map$/,
|
282 | /css.map$/
|
283 | ]
|
284 | : [
|
285 | /__MACOSX$/,
|
286 | /.DS_Store$/,
|
287 | /dependencyGraph.json$/,
|
288 | /debug.js$/,
|
289 | /debug.css$/,
|
290 | /build.json$/,
|
291 | /js.map$/,
|
292 | /css.map$/
|
293 | ],
|
294 |
|
295 |
|
296 |
|
297 | fileOptions: {
|
298 | mtime: new Date(),
|
299 | mode: 0o100664,
|
300 | compress: true,
|
301 | forceZip64Format: false
|
302 | },
|
303 |
|
304 | zipOptions: {
|
305 | forceZip64Format: false
|
306 | }
|
307 | })
|
308 | )
|
309 | }
|
310 |
|
311 | return webpackConfig
|
312 | }
|
313 |
|
314 | function copyPublicFiles(entry, distPageDir) {
|
315 | const pagePublicDir = rootPath(`${config.paths.page}/${entry}/public`)
|
316 | const plugins = []
|
317 |
|
318 | function getCopyOption(src) {
|
319 | return {
|
320 | from: src,
|
321 |
|
322 | to: distPageDir,
|
323 | ignore: ['.*']
|
324 | }
|
325 | }
|
326 |
|
327 |
|
328 | if (fs.existsSync(config.paths.public)) {
|
329 | plugins.push(new CopyWebpackPlugin([getCopyOption(config.paths.public)]))
|
330 | }
|
331 |
|
332 |
|
333 | if (fs.existsSync(pagePublicDir)) {
|
334 | plugins.push(new CopyWebpackPlugin([getCopyOption(pagePublicDir)]))
|
335 | }
|
336 |
|
337 | return plugins
|
338 | }
|