目的:想要通过npm命令按照我们的规则生成静态资源(webpack4以后还能做到很多性能优化的配置,我所知道的只有css、js分包,以达到资源快速加载快速呈现的效果)。
一、安装webpack
npm install --save-dev webpack
or
npm i webpack -D
webpack 4单独分离出webpack-cli,所以要安装webpack-cli
二、由于build和start都会有相同的配置,所以先搞一个公共配置文件webpack.base.conf.js
'use strict'
const path = require('path');
const utils = require('./utils');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js'
},
module: {
rules: [
{
test:/\.jsx$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]') // 图片名称也要加随机字符串,避免缓存
}
},
]
},
};
utils.js
'use strict'
const path = require('path');
exports.assetsPath = function (_path) {
return path.posix.join('static', _path)
}
三、配置webpack.dev.conf.js
'use strict'
//onst webpack = require('webpack');
const merge = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const devWebpackConfig = merge(baseWebpackConfig, {
devtool: 'cheap-module-eval-source-map', // 此选项控制是否生成,以及如何生成 source map
})
module.exports = devWebpackConfig
devtool的比较
![]()
详见https://www.webpackjs.com/configuration/devtool/
四、运行npm run start
package的script配置,通过webpack-dev-server实现自动监听并允许webpack
"start": "webpack-dev-server --config build/webpack.dev.conf.js",
报错:
Module not found: Error: Can't resolve 'fs' in 'D:\pro\ReactGame\node_modules\destroy'
于是安装了fs,再运行,还是一样的报错
参考了文章https://blog.csdn.net/flitrue/article/details/78055738
在webpack.base.conf.js添加配置
再次运行,报错:
Module not found: Error: Can't resolve 'net' in 'D:\pro\ReactGame\node_modules\express\lib'
那就在webpack.base.conf.js再添加配置
node: {
fs: 'empty',
net: 'empty',
}
try again,报错:
TypeError: merge is not a function
原因:merge引入方式不对,改成
const { merge } = require('webpack-merge');
终于启动不报错了。
五、配置webpack.prod.conf.js
'use strict'
const baseWebpackConfig = require('./webpack.base.conf');
const { merge } = require('webpack-merge');
const path = require('path');
const utils = require('./utils');
const webpack = require('webpack');
const ENV = process.env;
const webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
devtool: '#source-map',
output: {
path: path.resolve(__dirname, '../dist'),
filename: utils.assetsPath('js/[name].[chunkhash].js'),
/*
* chunkFilename用来打包require.ensure方法中引入的模块,如果该方法中没有引入任何模块则不会生成任何chunk块文件
* 比如在main.js文件中,require.ensure([],function(require){alert(11);}),这样不会打包块文件
* 只有这样才会打包生成块文件require.ensure([],function(require){alert(11);require('./greeter')})
* 或者这样require.ensure(['./greeter'],function(require){alert(11);})
* chunk的hash值只有在require.ensure中引入的模块发生变化,hash值才会改变
* 注意:对于不是在ensure方法中引入的模块,此属性不会生效,只能用CommonsChunkPlugin插件来提取
* */
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') // chunkFilename用来打包require.ensure方法中引入的模块
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.HashedModuleIdsPlugin(),
]
})
if (ENV.npm_config_report || ENV.npm_config_a) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig
六、运行npm run build
本来我用UglifyJs压缩js,但是最新版uglifyjs-webpack-plugin@2.2.0并不支持es6语法,github有给出说明:
所以在webpack.base.conf.js中配置
optimization: { // webpack 优化
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
mangle: true, // 混淆,默认也是开的,mangle也是可以配置很多选项的,具体看后面的链接
compress: {
drop_console: true, // 传true就是干掉所有的console.*这些函数的调用.
drop_debugger: true, // 干掉那些debugger;
pure_funcs: ['console.log'] // 如果你要干掉特定的函数比如console.info ,又想删掉后保留其参数中的副作用,那用pure_funcs来处理
}
}
})],
}
七、最终配置
package.json
{
"name": "reactgame",
"version": "1.0.0",
"description": "2048",
"main": "src/index.js",
"scripts": {
"start": "webpack-dev-server --config build/webpack.dev.conf.js",
"build": "node build/build.js"
},
"keywords": [
"myKeywords"
],
"author": "Abby",
"license": "ISC",
"dependencies": {
"ejs": "^3.1.5",
"express": "^4.17.1",
"fs": "0.0.1-security",
"path": "^0.12.7",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"chalk": "^4.1.0",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"ora": "^5.1.0",
"rimraf": "^3.0.2",
"supervisor": "^0.12.0",
"terser-webpack-plugin": "^4.1.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.1.3"
}
}
utils.js
'use strict'
const path = require('path');
exports.assetsPath = function (_path) {
return path.posix.join('static', _path)
}
webpack.base.conf.js
'use strict'
const path = require('path');
const utils = require('./utils');
const TerserPlugin = require('terser-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js'
},
module: {
rules: [
{
test:/\.jsx$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['es2015', 'react']
}
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({ //css的提取
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
]
},
optimization: { // webpack 优化
minimize: true,
minimizer: [new TerserPlugin({
terserOptions: {
mangle: true, // 混淆,默认也是开的,mangle也是可以配置很多选项的,具体看后面的链接
compress: {
drop_console: true, // 传true就是干掉所有的console.*这些函数的调用.
drop_debugger: true, // 干掉那些debugger;
pure_funcs: ['console.log'] // 如果你要干掉特定的函数比如console.info ,又想删掉后保留其参数中的副作用,那用pure_funcs来处理
}
}
})],
splitChunks: { // 分包
chunks: "all",
minSize: 100000, // 模块的最小体积
minChunks: 1, // 模块的最小被引用次数
maxAsyncRequests: 5, // 按需加载的最大并行请求数
maxInitialRequests: 3, // 一个入口最大并行请求数
automaticNameDelimiter: '~', // 文件名的连接符
name: true,
maxSize: 500000, // 模块的最小体积
cacheGroups: { // 缓存组
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
},
node: {
fs: 'empty',
net: 'empty',
}
};
webpack.dev.conf.js
'use strict'
//onst webpack = require('webpack');
const { merge } = require('webpack-merge');
const baseWebpackConfig = require('./webpack.base.conf');
const devWebpackConfig = merge(baseWebpackConfig, {
devtool: 'cheap-module-eval-source-map',
// devServer: {
// //hot: true,
// },
})
module.exports = devWebpackConfig
webpack.prod.conf.js
'use strict'
const baseWebpackConfig = require('./webpack.base.conf');
const { merge } = require('webpack-merge');
const path = require('path');
const utils = require('./utils');
const webpack = require('webpack');
const ENV = process.env;
const webpackConfig = merge(baseWebpackConfig, {
mode: 'production',
devtool: '#source-map',
output: {
path: path.resolve(__dirname, '../dist'),
filename: utils.assetsPath('js/[name].[chunkhash].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') // chunkFilename用来打包require.ensure方法中引入的模块
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"'
}),
new webpack.HashedModuleIdsPlugin(),
]
})
if (ENV.npm_config_report || ENV.npm_config_a) {
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
webpackConfig.plugins.push(new BundleAnalyzerPlugin())
}
module.exports = webpackConfig