webpack生产环境的总配置
提取css成单独文件
- 在webpack开发环境下我们往往不会让源目录中css文件在打包后单独生成一个css文件,但是这往往会使得打包后包含这些css文件内容的js文件体积臃肿,甚至可能出现闪屏现象,因为因为它的工作原理时是先加载js文件再去加载css文件。
- 场景需求:在webpack生产环境下我们往往会需要让源目录中css文件在打包后单独生成一个css文件
- 之前
通过'css-loader'和'style-loader'
将css代码统一整合进自动给构建出的js文件中,通过自动创建<style></style>
的方式自动引入css样式,现在我们需要单独的生成css文件。
- 我们可以使用配合插件
'mini-css-extract-plugin'
来完成我们的需求,这可以让源目录中css文件在打包后单独生成一个css文件(并且保持输出后的目录结构与源目录结构一致
),并且让构建后目录中的build/index.html
通过自动创建<link href="css/built.css" rel="stylesheet">
的方式引入css样式。
- 构建后目录中的
build/index.html
通过自动创建<link href="css/built.css" rel="stylesheet">
的方式引入css样式,这样子就不会出现闪屏现象了。
- 该构造目录的结构为:
- 执行webpack命令后自动创建的
build/index.html文件
的代码内容(注意css样式和je样式是自动引入的
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>webpack</title>
<link href="css/built.css" rel="stylesheet"></head>
<body>
<div id="box1"></div>
<div id="box2"></div>
<script type="text/javascript" src="js/built.js"></script></body>
</html>
- 该
webpack.config.js
的配置代码如下:
-
- 使用
'mini-css-extract-plugin'
插件并使用 MiniCssExtractPlugin.loader
这个来取代原先的'style-loade'
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 'style-loader'的作用是创建style标签,将样式放入
// 下面这个loader取代style-loader。
// 下面这个loader的作用:提取build/js/built.js中的css内容成单独文件
MiniCssExtractPlugin.loader,
// 将css文件整合到js文件中
'css-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: 'css/built.css'
})
],
mode: 'development'
};
css的兼容性处理
- 场景需求:我们在书写CSS页面时往往会遇到书写的的代码在一些浏览器下不兼容的问题,这会导致页面的样式加载不出来,因此我们在生产环境下需要对css做相应的兼容性处理。
- 解决方案之一:我们在这里使用postcss来处理css的兼容性问题。在webpack下想要使用postcss的功能需要借助使用
'postcss-loader'
这个Loader和这个Loader的插件'postcss-preset-env'
来实现css的兼容性处理。
- 第一步:下载
'postcss-loader'
和'postcss-preset-env'
即(cnpm i postcss-loader postcss-preset-env -D
)
- 注意点:Loader的两种写法:一种是使用Loader的默认配置写法(不修改其任何配置),一种是使用自定义配置写法(修改其相关配置)
- 默认配置写法举例代码说明:
module: {
rules: [
{
test: /\.css$/,
use: [
'css-loader'
]
}
]
}
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
//使用 'css-loader'的默认配置写法
'css-loader',
// 使用对象的写法来修改loader的配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// 使用postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
}
- 注意点:
'postcss-preset-env'
可以识别具体的环境从而加载指定的配置使得css精确的兼容到指定的浏览器的版本
- 注意点:
'postcss-preset-env'
可以帮postcss
找到package.json
中browserslist
里面的配置,然后通过这个'browserslist'
里面的配置加载指定的css兼容性样式
- 第二步:在
package.json
中去配置browserslist
,告知如何兼容css样式,书写的格式可以参考下面的写法(更多的配置可以在github上搜索关键字"browserslist"
):
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
- 注意点
:"development"
是开发环境,而"production"
是生产环境
- 注意点:在第二步中
运行命令webpack
后默认是看生产环境,即在package.json
中配置的"production"
会默认生效。注意这里是默认看生产环境(即"production"
)的配置,而不是去看webpack.config.js的mode配置,也就是说与webpack.config.js的mode配置是无关的。
- 注意点:如果我们想要让css兼容规则以开发环境的配置来做(即以
package.json
中配置的"development"
的规则来兼容),需要单独设置nodejs的环境变量(即在webpack.config.js
中添加process.env.NODE_ENV = 'development'
)
- 该构造目录的结构为:
- 该
webpack.config.js
的配置代码如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 设置nodejs环境变量让css兼容规则以开发环境的配置来做
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
//使用 'css-loader'的默认配置
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// 使用postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
})
],
mode: 'development'
};
压缩css文件
- 场景需求:压缩css文件
- 实现方式之一:引入压缩css的插件
'optimize-css-assets-webpack-plugin'
。(即cnpm i optimize-css-assets-webpack-plugin -D
)并使用,执行webpack命令
后即见效果。
- 该
webpack.config.js
的配置代码如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//引入压缩css的插件'optimize-css-assets-webpack-plugin'
//cnpm i optimize-css-assets-webpack-plugin -D
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 设置nodejs环境变量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'development'
};
js语法检查之eslint
- 场景需求:我们往往需要统一代码书写规范,例如检查出一些语法错误、格式不规范等问题并自动帮我们修改大部分的错误。
- 实现:语法检查最常用的工具是
eslint
。在webpack中如果想要使用eslint工具
,需要下载eslint-loader 和eslint
这两个依赖即(cnpm i eslint-loader eslint -D
)
- 注意点:我们只想检查自己写的源代码,并且相对来说第三方的库(
例如node_modules下的文件
)是不用检查的,所以我们需要设置eslint
的检查规则。即我们需要在在package.json
中设置'eslintConfig'
,规定好eslint
检查规则。书写的格式可以参考下面的写法:
- 注意点:在这里我们使用的
eslint
检查规则是airbnb风格指南(语言规范)
,也可以使用其他的检查规则,使用airbnb风格指南(语言规范)
需要再引入三个依赖即(eslint-config-airbnb-base、eslint-plugin-import、eslint
),所以需要下载cnpm i eslint-config-airbnb-base、eslint-plugin-import、eslint -D
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
- 该
webpack.config.js
的配置代码如下:
const { resolve } = require('path');
//引入插件'html-webpack-plugin'
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
// 打包后自动创建build/js/built.js
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自动修复eslint的错误
fix: true
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
// 以谁为模板
// 复制 './src/index.html' 文件
// 并自动引入 打包输出的所有资源(JS/CSS/IMG/iconFont)
template: './src/index.html'
})
],
//这里是开发模式的原因是好观察
mode: 'development'
};
- 注意点:如果我们再某个JS文件想要让某行代码忽略eslint的语法检测,我们可以在紧挨着该代码的上一行写
eslint-disable-next-line
,书写的格式可以参考下面的写法:
// 下一行eslint所有规则都失效(下一行不进行eslint检查)
// eslint-disable-next-line
console.log(add(2, 5));
js兼容性处理之babel
- 场景需求:当我们使用ES6、ES7等较为高级的语法来书写js代码时,执行webpack命令打包后默认是不会改变原JS代码的(
默认不会做兼容性处理
)。在这种情况下,如果该JS代码运行在低版本浏览器时,可能会出现报错等问题。所以我们需要让webpack打包时记得做js的兼容性处理。
- 解决方式之一:js兼容性处理可以使用babel。在webpack中如果想要使用babel工具,需要下载
babel-loader和@babel/core
即(cnpm i babel-loader和@babel/core -D
)
- 解决方式之一的注意点:在配合
@babel/preset-env
(即cnpm i @babel/preset-env -D
)可以对基本的js语法进行兼容性处理(例如箭头函数打包后变为普通函数、const打包后变为var等等
)。它的问题是只能转换基本语法,但是如promise等高级语法还是不能转换。
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets:['@babel/preset-env']
}
}
]
},
- 解决方式之二:由于解决方式一中
在配合 @babel/preset-env
使用的情况下依旧没有办法解决像promise等高级语法的转换,但是我们还是有这方面的js兼容性处理需求时可以使用@babel/polyfill
即(cnpm i @babel/polyfill -D
),
- 解决方式之二的注意点:使用方式是在下载
@babel/polyfill
之后,在入口文件(这里是src/js/index.js
)中引入该文件即可(即import '@babel/polyfill';
)
- 该构造目录为:
- 解决方式之二的注意点:这个
@babel/polyfill
可以解决全部的js兼容性处理,但是它的问题是将所有兼容性代码全部引入,体积太大了!
- 下面是
src/js/index.js
的代码:(将所有的兼容性代码引入入口文件并一起打包出去,使用此方式无需在webpack.config.js配置其他选项,直接在入口文件引入'@babel/polyfill'文件即可)
import '@babel/polyfill';
const add = (x, y) => {
return x + y;
};
console.log(add(2, 5));
const promise = new Promise(resolve => {
setTimeout(() => {
console.log('定时器执行完了~');
resolve();
}, 1000);
});
console.log(promise);
- 解决方式三:使用core-js配置做到按需加载(
即在有需要做兼容性处理的js代码就做兼容性处理
),我们需要先下载core-js
即(cnpm i core-js -D
),然后去配置core-js
,最后执行webpack命令即可看见效果。
- 解决方式三的注意点:在使用解决方式三
core-js
后不能够和解决方式二(即在入口文件中import '@babel/polyfill'
)共用,需要删除入口文件中的这一行(即import '@babel/polyfill'
)代码。
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 预设:指示babel做怎么样的兼容性处理
// 告诉'babel-loader'要进行怎么样的语法转换
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪个版本浏览器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
- 总结js兼容性处理配置的方式:(推荐使用按需加载来实现js兼容性处理)
压缩html和js文件
- 生产环境下会自动压缩js代码(即在
webpack.config.js
中配置mode: 'production'
)
- 我们可以观察到在
webpack.config.js
中配置mode: 'production'
后会启用UglifyJsPlugin插件,该插件会去压缩JS代码。
选项 |
描述 |
特点 |
development |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置 为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin |
能让代码本地调试 运行的环境 |
production |
会将 DefinePlugin 中 process.env.NODE_ENV 的值设置 为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin和UglifyJsPlugin |
能让代码优化上线 运行的环境 |
- 压缩JS代码的
webpack.config.js
的配置代码如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
// 生产环境下会自动压缩js代码
mode: 'production'
};
- 压缩HTML文件(
记住HTML的标签是做不了兼容性处理的
),可以使用HtmlWebpackPlugin插件
来压缩HTML文件。
- 之前我们用
HtmlWebpackPlugin插件
来创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS),现在我们还可以用它来帮我们压缩HTML文件。
- 压缩HTML文件的
webpack.config.js
的配置代码如下:
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
],
mode: 'production'
}
综合案例:生产环境的基本总配置
-
- 注意点:注意路径的引入问题:在不同的目录结构中要使用正确的路径引用对应的资源
-
- 注意点:有多个Loader对同一类型的文件进行处理时一定要注意顺序!!!,例如在处理.less文件时webpack.config.js的代码如下:(此时打包后的css文件是单独的文件并自动通过
<link>
的方式被引入HTML页面)
// 为了复用loader的分离loader写法
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中配置'browserslist'
// css兼容规则默认以生产环境的配置来做
// 如果需要以开发环境的配置来做需单独设置nodejs的环境变量
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
/**
* 注意顺序!!!!!!
* 顺序是使用'less-loader'先转为.css文件
* 在执行'postcss-loader'做css的兼容性处理
* 在执行'css-loader'将css代码写入打包后自动构建的js文件中
* 再去执行MiniCssExtractPlugin.loader
* 将css样式以link标签的方式引入页面
*/
use: [...commonCssLoader, 'less-loader']
},
]
}
]
},
-
- 注意点:当js兼容性处理之babel和js语法检查之eslint遇到一起时,它们都要对js文件进行处理时,我们要先先执行eslint语法检查在执行babel兼容性处理。可以在
webpack.config.js
的Loader配置中添加 enforce: 'pre'
来确保优先执行。
-
- 注意点:js语法检查之eslint需要我们在
package.json
中设置'eslintConfig'
,规定好eslint检查规则。即:
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
-
- 注意点:在处理css文件的兼容性处理中执行
webpack
命令默认是看生产环境,即在package.json
中配置的"production"
规则会默认生效。如果我们想要让css兼容规则以开发环境的配置来做,需要单独设置nodejs的环境变量(即在webpack.config.js中添加process.env.NODE_ENV = 'development'
)
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
- 此时的webpack.config.js的总配置为:
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
//压缩css代码
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
//创建一个空的HTML,自动引入打包输出的所有资源(JS/CSS),压缩HTML文件
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定义nodejs环境变量:决定使用package.json中"browserslist"的哪个环境
// 在处理css文件的兼容性处理中执行`webpack`命令默认是看生产环境("production")
// 如果想要让css兼容规则以开发环境的配置来做需要做如下配置:
process.env.NODE_ENV = 'production';
// 复用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
//入口文件
entry: './src/js/index.js',
//输出目录路径
output: {
filename: 'js/built.js',
//需要引入 const { resolve } = require('path');
//打包构建后的目录结构要与源目录结构保持一致
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
// 确保优先执行,不在考虑书写的先后顺序
enforce: 'pre',
//使用eslint需要在package.json中配置'eslintConfig'
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
//重命名文件路径及名称与源目录结构保持一致
filename: 'css/built.css'
}),
//只需要如此调用就可以压缩css代码无需再多余操作
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
//压缩html代码
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
//生产环境自动压缩js代码
mode: 'production'
};
{
"name": "webpack_code",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.8.4",
"@babel/polyfill": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"add-asset-html-webpack-plugin": "^3.1.3",
"babel": "^6.23.0",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.4.2",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.0.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.1",
"file-loader": "^5.0.2",
"html-loader": "^0.5.5",
"html-webpack-plugin": "^3.2.0",
"less": "^3.11.1",
"less-loader": "^5.0.0",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss-loader": "^3.0.0",
"postcss-preset-env": "^6.7.0",
"style-loader": "^1.1.3",
"terser-webpack-plugin": "^2.3.5",
"thread-loader": "^2.1.3",
"url-loader": "^3.0.0",
"webpack": "^4.41.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"workbox-webpack-plugin": "^5.0.0"
},
"dependencies": {
"jquery": "^3.4.1"
},
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
},
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
},
"sideEffects": [
"*.css"
]
}
发表评论
还没有评论,快来抢沙发吧!