UNPKG

6.82 kBJavaScriptView Raw
1/* eslint-disable global-require */
2const _ = require('lodash');
3const path = require('path');
4const webpack = require('webpack');
5const merge = require('webpack-merge');
6const openBrowser = require('opn');
7
8const {getConfig, getRollupConfig} = require('./config/default');
9const {getOptimizationConfig} = require('./config/optimization');
10const {getPlugins} = require('./config/plugins');
11const {getLoaders} = require('./config/loaders');
12const getNodeConfig = require('./config/node');
13const {getDevServerConfig} = require('./config/devServer');
14
15function getDevTool(config) {
16 if (!config.sourceMap) return false;
17 if (config.isProduction) return '#source-map';
18 return '#eval-source-map';
19}
20
21function getFileName(config) {
22 if (config.library || !config.appendHash) return '[name].js';
23 // webpack does not support base62 encoding in contenthash yet
24 if (config.isProduction) return 'js/[name].[contenthash:7].js';
25 return 'js/[name].js';
26}
27
28// options is {env, config, webpackConfig}
29// env can be developement or production
30// config gets merged into our default config
31// webpackConfig gets merged into final webpack config
32function getWebpackConfig(options = {}) {
33 const env = options.env || process.env.NODE_ENV || 'development';
34
35 const config = getConfig(options.config, env);
36 options.config._final = config;
37 const webpackConfig = options.webpackConfig || {};
38
39 const isProduction = config.isProduction;
40
41 // correct NODE_ENV is important for vue-loader to correctly minify files
42 process.env.NODE_ENV = isProduction ? 'production' : 'development';
43
44 const cwd = config.cwd;
45
46 config.sourcePath = path.join(cwd, config.sourcePath);
47 config.destPath = path.join(cwd, config.destPath);
48
49 const entry = {};
50 _.forEach(config.entry, (value, key) => {
51 entry[key] = path.join(config.sourcePath, value);
52 });
53
54 const baseConfig = {
55 target: 'web',
56 mode: isProduction ? 'production' : 'development',
57 context: cwd,
58 entry,
59 output: {
60 path: config.destPath,
61 publicPath: config.publicUrl,
62 filename: getFileName(config),
63 chunkFilename: getFileName(config),
64 },
65 resolve: {
66 extensions: ['.wasm', '.mjs', '.js', '.mjsx', '.jsx', '.vue', '.json'],
67 modules: [
68 path.join(cwd, 'node_modules'),
69 path.join(__dirname, 'node_modules'),
70 ],
71 alias: {
72 '@': config.sourcePath,
73 res: config.sourcePath,
74 js: path.join(config.sourcePath, 'js'),
75 assets: path.join(config.sourcePath, 'assets'),
76 components: path.join(config.sourcePath, 'js', 'components'),
77 css: path.join(config.sourcePath, 'css'),
78 img: path.join(config.sourcePath, 'img'),
79 },
80 },
81 resolveLoader: {
82 modules: [
83 path.join(cwd, 'node_modules'),
84 path.join(__dirname, 'node_modules'),
85 ],
86 },
87 module: {
88 // don't parse these modules to speed up things
89 noParse: /node_modules(.*)\/(firepad|jquery)\//,
90 rules: getLoaders(config),
91 },
92 node: getNodeConfig(config),
93 optimization: getOptimizationConfig(config),
94 plugins: getPlugins(config),
95 devtool: getDevTool(config),
96 };
97
98 if (config.library) {
99 baseConfig.output.libraryTarget = config.libraryFormat || 'umd';
100 baseConfig.output.umdNamedDefine = true;
101 baseConfig.output.library = config.library === true ? 'Lib' : config.library;
102 }
103
104 if (!isProduction) {
105 // for working with hmr in web workers
106 // https://github.com/webpack/webpack/issues/6642
107 baseConfig.output.globalObject = 'this';
108
109 // disable performace hints
110 baseConfig.performance = {hints: false};
111 }
112
113 return merge(baseConfig, webpackConfig);
114}
115
116function getProdConfig({config, webpackConfig}) {
117 return getConfig({env: 'production', config, webpackConfig});
118}
119
120function getDevConfig({config, webpackConfig}) {
121 return getConfig({env: 'development', config, webpackConfig});
122}
123
124function runWebpack({env, config, webpackConfig}) {
125 const formatStats = require('./util/formatStats');
126 return new Promise((resolve, reject) => {
127 const finalWebpackConfig = getWebpackConfig({env, config, webpackConfig});
128
129 // run webpack
130 webpack(finalWebpackConfig, (err, stats) => {
131 if (err) {
132 reject(err);
133 return;
134 }
135
136 console.log(formatStats(stats, config.destPath));
137 resolve();
138 });
139 });
140}
141
142function runDevWebpack({config = {}, webpackConfig = {}} = {}) {
143 return runWebpack({env: 'development', config, webpackConfig});
144}
145
146function runProdWebpack({config = {}, webpackConfig = {}} = {}) {
147 return runWebpack({env: 'production', config, webpackConfig});
148}
149
150function runDevServer({config = {}, webpackConfig = {}} = {}) {
151 // eslint-disable-next-line
152 const WebpackDevServer = require('webpack-dev-server');
153
154 const finalConfig = getConfig(config, 'development');
155 finalConfig.isDevServer = true;
156 finalConfig.destPath = '.';
157 finalConfig.publicUrl = '/';
158
159 const devServerConfig = getDevServerConfig(finalConfig);
160 const finalWebpackConfig = getWebpackConfig({
161 env: 'development',
162 devServer: true,
163 config: finalConfig,
164 webpackConfig,
165 });
166
167 // add hot-reload related code to entry chunks
168 WebpackDevServer.addDevServerEntrypoints(finalWebpackConfig, {
169 contentBase: devServerConfig.contentBase,
170 hot: true,
171 host: 'localhost',
172 });
173
174 let isFirstCompile = true;
175 const compiler = webpack(finalWebpackConfig);
176 compiler.hooks.done.tap('sm-webpack-dev-server', (stats) => {
177 if (stats.hasErrors()) return;
178
179 if (isFirstCompile) {
180 isFirstCompile = false;
181 if (finalConfig.openBrowser) {
182 const port = devServerConfig.port;
183 const protocol = devServerConfig.https ? 'https' : 'http';
184 openBrowser(`${protocol}://localhost:${port}`);
185 }
186 }
187 });
188
189 // Start a webpack-dev-server
190 const server = new WebpackDevServer(compiler, devServerConfig);
191
192 return new Promise((resolve, reject) => {
193 server.listen(devServerConfig.port, devServerConfig.host, (err) => {
194 if (err) {
195 reject(err);
196 return;
197 }
198
199 resolve();
200 });
201 });
202}
203
204function runRollup(options = {}) {
205 const rollup = require('rollup');
206
207 const env = process.env.NODE_ENV || 'production';
208 const config = getRollupConfig(options.config || {}, env);
209 const cwd = config.cwd;
210
211 config.entry = path.resolve(cwd, config.entry);
212 config.dest = path.resolve(cwd, config.dest);
213
214 const {getBabelConfig} = require('./config/babel');
215 const plugins = [
216 require('rollup-plugin-babel')({
217 exclude: 'node_modules/**',
218 ...getBabelConfig(config),
219 }),
220 ];
221
222 if (config.minify) {
223 plugins.push(
224 require('rollup-plugin-uglify')()
225 );
226 }
227
228 return rollup.rollup({
229 entry: config.entry,
230 plugins,
231 }).then((bundle) => {
232 bundle.write({
233 format: config.libraryFormat || 'umd',
234 moduleName: config.library === true ? 'Lib' : config.library,
235 dest: config.dest,
236 sourceMap: config.sourceMap,
237 });
238 });
239}
240
241module.exports = {
242 getWebpackConfig,
243 getProdConfig,
244 getDevConfig,
245 runWebpack,
246 runDevWebpack,
247 runProdWebpack,
248 runDevServer,
249 runRollup,
250};