UNPKG

5.97 kBJavaScriptView Raw
1const path = require('path')
2const fs = require('fs')
3
4const webpack = require('webpack')
5const ExtractTextPlugin = require('extract-text-webpack-plugin')
6const cssnano = require('cssnano')
7
8const { clientConfig, serverConfig, cordovaConfig } = require('./webpack.config')
9const { ExtractTextLoader } = require('./common')
10
11// get the last argument, see the dev.js
12const argv = process.argv[2]
13
14const commonPlugins = [
15 new webpack.DefinePlugin({
16 'process.env.TEST': false,
17 'process.env.NODE_ENV': '"production"',
18 }),
19 new ExtractTextPlugin({
20 filename: 'styles_[contenthash:7].css',
21 allChunks: false, // default, so when using System.import(), css will be inlined into <style />
22 }),
23 new webpack.optimize.AggressiveMergingPlugin(),
24 new webpack.optimize.UglifyJsPlugin({
25 compress: {
26 warnings: false,
27 },
28 sourceMap: false,
29 comments: false,
30 'screw-ie8': true,
31 }),
32]
33
34
35/**
36 * Client
37 */
38
39clientConfig.module.rules.push(...ExtractTextLoader)
40clientConfig.plugins.push(...commonPlugins)
41const commonsChunk = new webpack.optimize.CommonsChunkPlugin({
42 name: 'vendor',
43 minChunks: ({ resource }) => /node_modules/.test(resource), // could use /node_modules.*\.jsx?$/ to only process js
44})
45clientConfig.plugins.push(new webpack.HashedModuleIdsPlugin(), commonsChunk)
46// clientConfig.plugins.push(commonsChunk, new require('webpack-chunk-hash'))
47
48/*
49 There are 3+ ways to dynamically create vendor chunk for long term caching using CommonsChunkPlugin
50 After creating a commonChunk
51 new webpack.optimize.CommonsChunkPlugin({
52 name: 'vendor',
53 minChunks: ({ resource }) => /node_modules/.test(resource),
54 })
55
56 1) Add new require('webpack-md5-hash') or require('webpack-chunk-hash')
57 The hash will be based on content, the manifest webpackJsonp function will be in the entry chunk, in this case the vendor chunk
58 There will output 2 files: vendor.xx.js and client.xx.js
59 vendor.xx.js is the entry chunk and will be loaded first
60 2) Add another commonChunk
61 new webpack.optimize.CommonsChunkPlugin('manifest') <-- can be any name, such as 'meta'
62 this will create a manifest.[xxx].js or meta.[xxx].js which contains the webpackJsonp functions
63 There will create 3 files: manifest.xx.js, vendor.xx.js and client.xx.js
64 When the client code changes, the xx in client.xx.js and the xx in manifest.xx.js will change
65 the xx in vendor.xx.js will be the same
66 no need extra plugin, but will results in 3 http requests
67 3) Add new require('chunk-manifest-webpack-plugin') after adding new webpack.optimize.CommonsChunkPlugin('manifest')
68 This plugin extract the manifest into a json file
69 Then will need inline-manifest-webpack-plugin to insert the json into the intial html along with html-webpack-plugin
70 This will result in 2 files: vendor.xx.js and client.xx.js
71
72 ** I have decided to go for option 1 as it seems simplest, clients only need to make 2 http request, but need to be dependent on the md5 plugins
73*/
74
75
76if (argv !== 'cordovaOnly') {
77 webpack(clientConfig).run((err, stats) => {
78 if (err) throw err
79 console.log('Client Bundles \n', stats.toString({
80 colors: true,
81 }), '\n')
82 // cssnano, temparory work around
83 const assets = require(path.resolve('build/webpack-assets.json')) // eslint-disable-line import/no-dynamic-require
84 for (const entry in assets) { // eslint-disable-line
85 const filename = assets[entry].css
86 if (filename) {
87 const filePath = path.resolve('build/public', filename.replace(/^\/+/, ''))
88 fs.readFile(filePath, (e, css) => {
89 cssnano.process(css, { discardComments: { removeAll: true } })
90 .then(result => {
91 fs.writeFile(filePath, result.css, () => {})
92 })
93 })
94 }
95 }
96 })
97}
98
99/**
100 * Server
101 */
102
103serverConfig.module.rules.push(ExtractTextLoader[1]) // handle the css module
104serverConfig.plugins.push(...commonPlugins)
105// remove the ExtractTextPlugin
106serverConfig.plugins = serverConfig.plugins.filter(p => !(p instanceof ExtractTextPlugin))
107// re-add the ExtractTextPlugin with new option
108serverConfig.plugins.push(new ExtractTextPlugin({ filename: 'styles.css', allChunks: true })) // set allChunks to true to move all css into styles.css which will be deleted in the following build step
109
110if (argv !== 'cordovaOnly') {
111 webpack(serverConfig).run((err, stats) => {
112 if (err) throw err
113 console.log('Server Bundle \n', stats.toString({
114 colors: true,
115 }), '\n')
116 require('child_process').exec('rm build/server/styles.css', () => {}) // delele the styles.css in the server folder
117 // try {
118 // const styleFile = _root + '/build/server/styles.css'
119 // fs.statSync(styleFile) && fs.unlinkSync(styleFile)
120 // } catch(e) {/*do nothing*/}
121 // file loader may also result in duplicated files from shared React components
122 })
123}
124
125/**
126 * Cordova
127 */
128
129cordovaConfig.module.rules.push(...ExtractTextLoader)
130cordovaConfig.plugins.push(...commonPlugins)
131
132// remove the ExtractTextPlugin
133cordovaConfig.plugins = cordovaConfig.plugins.filter(p => !(p instanceof ExtractTextPlugin))
134// re-add the ExtractTextPlugin with new option
135cordovaConfig.plugins.push(new ExtractTextPlugin({ filename: 'styles.css', allChunks: true }))
136
137if (argv === 'all' || argv === 'cordovaOnly') {
138 webpack(cordovaConfig).run((err, stats) => { // eslint-disable-line no-unused-expressions
139 if (err) throw err
140 console.log('Cordova Bundles \n', stats.toString({
141 colors: true,
142 }), '\n')
143
144 const filePath = path.resolve(cordovaConfig.output.path, 'styles.css')
145 fs.readFile(filePath, (e, css) => {
146 cssnano.process(css, { discardComments: { removeAll: true } })
147 .then(result => {
148 fs.writeFile(filePath, result.css, () => {})
149 })
150 })
151 })
152}