乐趣区

[ webpack4 ] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇

GitHub 完整配置文件地址:https://github.com/yhtx1997/w…
由于篇幅过长分三次发布,建议按顺序看 [webpack4] 配置属于自己的打包系统教程(一)—— 基础配置篇 [webpack4] 配置属于自己的打包系统教程(二)—— 资源配置篇 [webpack4] 配置属于自己的打包系统教程(最终篇)—— 环境配置篇
环境配置篇
主要内容

开发环境生产环境分离
实时预览,热更新
webpack-dev-server 其他常用
代码复用处理

开发环境和生产环境
到了这一步,该讲讲开发环境模式和生产环境模式了

开发环境是自己开发时用的,需要有实时编译功能、模块热替换功能(更新文件不用完全更新页面)、错误提示到具体哪个文件几行
生产环境是放到线上给用户使用的,需要代码压缩功能

配置代码组件化
我们先把之前配置好的 webpack 配置文件改下名,改名 webpack.common.js,意思是开发环境和生产环境都需要的,将代码压缩之类的挪到生产配置下之后安装 webpack-merge,官方推荐的是为每个环境写单独的 webpack 文件
虽然有简单的方法实现但是依然推荐写单独的配置文件,因为在这样的配置方式你可以更清楚你自己在做什么,还可以让你的配置更加个性(自定义)
安装 webpack-merge
npm install webpack-merge -D
新建开发环境配置
我们新建一个 js 文件,命名为 webpack.dev.js,添加如下代码
const merge = require(‘webpack-merge’);// 合并配置
const common = require(‘./webpack.common.js’);// 引入公共配置

module.exports = merge(common, {
mode: ‘development’,// 声明是开发环境
// 关于 dev 的配置
})
新建开发环境配置
我们新建一个 js 文件,命名为 webpack.prod.js
添加如下代码
const merge = require(‘webpack-merge’);// 合并配置
const UglifyJSPlugin = require(‘uglifyjs-webpack-plugin’);// 用来压缩 js 代码
const common = require(‘./webpack.common.js’);// 引入公共配置

module.exports = merge(common, {
mode: ‘production’,// 声明是生产环境
// 关于 prod 的配置
});
开发环境
实时预览
跟着配置并操作的小伙伴可能发现了,每次修改后都需要手动在命令行输入命令,并且还要刷新浏览器才能看到最新的效果
那么现在来解决这两个问题,方法就是使用 webpack-dev-server
安装
npm install webpack-dev-server -D
配置

实时预览
模块热更新
自定义请求代理
自定义 ip 及端口
注:使用 webpack-dev-server 并不会编译到本地文件,而是放到内存中

const merge = require(‘webpack-merge’);
const common = require(‘./webpack.common.js’);
const path = require(‘path’);
const webpack = require(‘webpack’);

module.exports = merge(common, {
mode: ‘development’,
plugins: [
new webpack.NamedModulesPlugin(),// 模块热更新
new webpack.HotModuleReplacementPlugin()// 模块热更新
],
devServer: {
contentBase: path.join(__dirname, ‘dist’),// 预览的目录,写出口目录的绝对路径
hot: true,// 模块热更新
host: ‘localhost’,// 默认值 也可以改为 127.0.0.1 或者其他
port: 8080,
proxy: {
‘/api’: ‘http://localhost:3000’// 请求到 /api/users 现在会被代理到请求 http://localhost:3000/api/users
}

}
})
接下来加入错误提示以及将生成 HTML 的代码从公共配置(webpack.common.js)拿到这里
因为开发和生产有些许不一样,我又不知道怎样简单配置,所以开发环境和生产环境我都会放一个生成 HTML 的代码
生产环境

每次打包都要清理掉旧文件
所有代码都要进行压缩
重复的 js 代码,需要只有一个就好

文件清理
从公共配置(webpack.common.js)将之前文件清理的代码拿过来放到这里
const merge = require(‘webpack-merge’);
const common = require(‘./webpack.common.js’);
const CleanWebpackPlugin = require(‘clean-webpack-plugin’);

module.exports = merge(common, {
mode: ‘production’,
plugins: [
new CleanWebpackPlugin([‘dist’]),
new HtmlWebpackPlugin({
title: ‘2048’,
template: ‘./src/index.html’,
minify: true,//HTML 代码压缩
hash: true
}),
],
})
代码压缩
先安装压缩代码的插件
npm install uglifyjs-webpack-plugin -D
npm install optimize-css-assets-webpack-plugin -D

uglifyjs-webpack-plugin 是 js 压缩插件
optimize-css-assets-webpack-plugin 是推荐和

const UglifyJsPlugin = require(“uglifyjs-webpack-plugin”);
const OptimizeCSSAssetsPlugin = require(“optimize-css-assets-webpack-plugin”);
复用代码分离
假设需要使用 jQuery 来辅助开发,我在 a.js b.js 两个文件都引入了 jQuery,将 a.js b.js 打包成 a.min.js b.min.js,这时看他们的体积会比原来大很多,且 a 和 b 的代码中都包含完整的 jQuery 代码
为了解决这种情况,我们需要将 jQuery 这种复用的代码分离到单独的文件
在将环境设置为生产环境时默认开启了很多功能,其中 SplitChunksPlugin 就是用于避免重复依赖的
在我们不配置时 默认配置是这样的
optimization: {
splitChunks: {
chunks: ‘async’,
minSize: 30000,
minChunks: 1,
}
}

chunks: 表示哪些代码需要优化,有三个可选值:initial(初始块)、async(按需加载块)、all(全部块),默认为 async 改成 all 支持所有的
minSize: 这个文件最少是多少才去优化,默认为 30000 实际测试是文件大于 30 kb,在 31kb 时开始优化
minChunks: 最少引用几次才去优化,默认为 1 实际测试为在只引用一次的情况不优化,只有大于它才优化
注:还有其他属性个人感觉不常用就没写,了解更多可以看这里

最终代码汇总
最终公共配置 webpack.common.js 代码如下
const path = require(‘path’);
const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);

module.exports = {
entry: {
512:’./src/js/512.js’,
1024:’./src/js/1024.js’,
2048:’./src/js/2048.js’,
},
plugins: [
new MiniCssExtractPlugin({
filename: “css/[name].css”
})
],
output: {
filename: “js/[name].js”,
path: path.resolve(__dirname, ‘dist’)
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: ‘babel-loader’,
options: {
presets: [‘@babel/preset-env’]
}
}
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
‘css-loader’,
‘postcss-loader’,
‘sass-loader’,
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
‘file-loader’
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
‘file-loader’
]
},
{
test: /\.(csv|tsv)$/,
use: [
‘csv-loader’
]
},
{
test: /\.xml$/,
use: [
‘xml-loader’
]
}
]
},

}
最终开发环境 webpack.dev.js 代码如下
const merge = require(‘webpack-merge’);
const common = require(‘./webpack.common.js’);
const path = require(‘path’);
const webpack = require(‘webpack’);
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);

module.exports = merge(common, {
mode: ‘development’,
plugins: [
new HtmlWebpackPlugin({
title: ‘2048’,
template: ‘./src/index.html’,
minify: false,
hash: true
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
devtool: ‘inline-source-map’,
devServer: {
contentBase: path.join(__dirname, ‘dist’),
hot: true,
host: ‘localhost’,
port: 8080,
proxy: {
‘/api’: ‘http://localhost:3000’
}

}
})
最终生产环境 webpack.prod.js 代码如下
const merge = require(‘webpack-merge’);
const common = require(‘./webpack.common.js’);
const UglifyJsPlugin = require(“uglifyjs-webpack-plugin”);
const OptimizeCSSAssetsPlugin = require(“optimize-css-assets-webpack-plugin”);
const HtmlWebpackPlugin = require(‘html-webpack-plugin’);
const CleanWebpackPlugin = require(‘clean-webpack-plugin’);

module.exports = merge(common, {
mode: ‘production’,
plugins: [
new CleanWebpackPlugin([‘dist’]),
new HtmlWebpackPlugin({
title: ‘2048’,
template: ‘./src/index.html’,
minify: true,
hash: true
}),
],
optimization: {
splitChunks: {
chunks: ‘all’
},
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin({})
],
}
});
npm 项目配置代码 package.json 代码如下
{
“name”: “2048”,
“version”: “1.0.0”,
“description”: “”,
“private”: true,
“main”: “index.js”,
“scripts”: {
“dev”: “webpack-dev-server –open –config webpack.dev.js”,
“build”: “webpack –config webpack.prod.js”
},
“keywords”: [],
“author”: “”,
“license”: “ISC”,
“dependencies”: {
“webpack”: “^4.28.3”
},
“devDependencies”: {
“@babel/core”: “^7.2.2”,
“@babel/preset-env”: “^7.2.3”,
“autoprefixer”: “^9.4.3”,
“babel-loader”: “^8.0.4”,
“clean-webpack-plugin”: “^1.0.0”,
“css-loader”: “^2.1.0”,
“csv-loader”: “^3.0.2”,
“extract-text-webpack-plugin”: “^4.0.0-beta.0”,
“file-loader”: “^3.0.1”,
“html-webpack-plugin”: “^3.2.0”,
“mini-css-extract-plugin”: “^0.5.0”,
“node-sass”: “^4.11.0”,
“optimize-css-assets-webpack-plugin”: “^5.0.1”,
“postcss”: “^7.0.7”,
“postcss-loader”: “^3.0.0”,
“sass-loader”: “^7.1.0”,
“style-loader”: “^0.23.1”,
“uglifyjs-webpack-plugin”: “^2.1.1”,
“webpack-cli”: “^3.1.2”,
“webpack-dev-server”: “^3.1.14”,
“webpack-merge”: “^4.1.5”,
“xml-loader”: “^1.2.1”
}
}

退出移动版