已同步语雀:www.yuque.com/go/doc/5319…
github:www.yuque.com/go/doc/5319…
本系列为Webpack——入门篇,包括:
1、Webpack——【入门篇-上篇】juejin.cn/post/695439…
2、Webpack——【入门篇-中篇】【本篇】juejin.cn/post/695438…
3、Webpack——【入门篇-下篇】juejin.cn/post/695438…
09 构建环境介绍
以上是开发环境的配置,mode: 'development'
生产环境还需考虑的问题:
- css 文件从 js 文件中提取出来:开发环境打包结果,字体文件和图片打包出独立的文件,目录由 options.outputName 决定
- 而 css、less 样式文件经过 css-loader 处理,变成 common.js 模块加载到 js 中,这样会造成 js 文件特别大,加载慢,且样式最终需要经过 style-loader 处理插到 html 中,会导致页面出现闪屏的问题
- 代码统一进行压缩
- 兼容性问题:样式、部分 js,比如某些样式需要加前缀才能在低版本浏览器正常使用
10 提取 css 成单独文件(mini-css-extract-plugin)
npm i mini-css-extract-plugin -D
webpack.config.js
...
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module: {
rules:[
{
test: /\.css/,
use: [//使用哪些loader,执行顺序是从下至上;或者说从右到左,依次执行
// npm i style-loader css-loader -D
// 创建style标签,将js中的样式资源插入到标签中,添加到head中生效
// 'style-loader',
// 取代style-loader,提取js中的css成单独文件
MiniCssExtractPlugin.loader,
// 将css文件变成commonjs模块加载js中,里面内容是样式字符串
'css-loader'
],
},
]
},
plugins: [
// new MiniCssExtractPlugin()
new MiniCssExtractPlugin({
filename: 'css/index.css' //指定提取css文件的在dist下的目录
})
]
复制代码
执行 webpack,可以看到打包生成 dist/css/index.css,dist/index.html 中引入 css 文件
<link href="/main.css" rel="stylesheet" />
复制代码
在浏览器打开 index.html,可以看到如下
样式通过 link 标签引入,不会有闪的问题
11 css 兼容性处理(postcss)
npm i postcss-loader postcss-preset-env -D
webpack.config.js
...
// 设置node环境变量
process.env.NODE_ENV = "development";
module: {
rules:[
{
test: /\.css/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
/*
css 兼容性处理:postcss --> postcss-loader plugin:postcss-preset-env
*/
//npm i postcss-loader postcss-preset-env -D
// 使用
{
loader: "postcss-loader",
options: {
postcssOptions: {
//postcss的插件
//帮postcss找到package.json中browserlist里面的配置,可识别环境,通过配置加载指定的css兼容性样式
plugins: [
[
"postcss-preset-env"
]
],
/*
"browserslist": {
// 开发环境 --> 设置node环境变量:process.env.NODE_ENV = "development"
"development": [
"last 1 chrome version", //兼容chrome最近一个版本
"last 1 firefox version",
"last 1 safari version"
],
// 生产环境:默认看生产环境 跟webpack.config.js mode无关
"production":[
">0.2%", //兼容99.8%的浏览器
"not dead", //兼容没有dead的浏览器
"not op_mini all"
]
}
*/
},
},
},
],
},
]
}
复制代码
package.json
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production":[
">0.2%",
"not dead",
"not op_mini all"
]
}
复制代码
index.css
body{
...
display: flex;
backface-visibility: hidden;
}
复制代码
执行 webpack,可以看到打包生成 dist/css/index.css
body{
...
display: flex;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
复制代码
注释package.json中process.env.NODE_ENV = "development";
执行 webpack,可以看到打包生成 dist/css/index.css
body{
...
display: -webkit-flex;
display: flex;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
复制代码
12 压缩css(optimize-css-assets-webpack-plugin)
npm i optimize-css-assets-webpack-plugin -D
webpack.config.js
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
...
plugins: [
...
// 压缩css
// npm i optimize-css-assets-webpack-plugin -D
new OptimizeCssAssetsWebpackPlugin(),
]
复制代码
执行 webpack,可以看到打包生成 dist/css/index.css已经被压缩,对比压缩前后css文件大小,从2.58kb变成2.34kb
body{height:100%;width:100%;background-color:red;display:flex;-webkit-backface-visibility:hidden;backface-visibility:hidden}@font-face{font-family:iconfont;src:url(/font/67b199ed6b.eot);src:url(/font/67b199ed6b.eot#iefix) format("embedded-opentype"),url("data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAASoAAsAAAAACXQAAARcAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDQAqFYIRbATYCJAMYCw4ABCAFhG0HZhsXCBEVpDmQfZFg207YPiRFXdMUDu9LHUnXRBC/9pt99+6+GN7EEvxIxxsekjZLEC00qIRMJpOKNS+Bn77TXqDZoDA0bU/Y9Cx9XVKZ9ntr0475da0wUXVMie3y0zPyz7PC5QO0jA1g0v7PMdOlRYHkt9lcMoLWtDfA8YAGFpG23YHcgRXIifoNY5cXeZ5A0wQjlHWfoChgy/RpgTjLz00HdsIgV5BDXV0VrM0QD8BQT/3USwDuvd+PP7AINkjKAvS5uzneWeD2JvvNP1qbqA2SHAQIh7OBbaJAH8jEZaHjAmhBoo+mKR9OtwqgqS5Jnzlv8t78evNPJAIYVhJJNuRoahv/8ihkpZCICnRFG2E3kyWf2Rabgs8cNpnPPEG18hfUCaj8B+skUA04pokPgBgDHdfnCAl92LykypSUEJeX4nJrgXjWJ42l/WROoIFD0KY/ba+9X5uUPtx2y0sKUMjccTlgIRMrvUyfHLxJaTeYOaAjc8fgCKV969aDurKUwtu3o2/dikJ3YgAFAbiJKHH3buwdys/hBlwsA3TY8YBMzkz70qB0du7sINkmlTU1VTnDSGs3Ym6svzlynWzubKZwZ3sjf+0hOTo+rE3AHZ6WHZSN5W04qsiYP5I0JcU1H4uitAsRmpFhzBKCQeksNLCxjZQmZpfahbHcqYhM8AafoHbVkzEzUeZu9VUSLGfvKCuqf17ln7Zs25PaCt/oK2Y+Nl7W85C5qirdmyf5P2smtlNPq/rA+4HXboo2mhZy7Gv3zph5gOhp2unTtGmD63Dte2h9KDLM1+3ibrdkr6hOxKphLFtFraXWr15dD6RUyIVyt1oHFyy4rVzp9gxE8eaio/rlNeWxq7OzK/b36Y+O0l4Lqpc8HGWFxyXl+xyVjVi/rOZ4f1LrpmXLyBzUHBXLWn4ORbDe/y38hvnQe/w2W41Wvg7jkb0Dkd+wALqPUn6csbRjOD7Zn6fB2z/GgUZTiDip0rf54ori124fU1dUn5iuvhYj86t5TmgC/aT0RL0GQHFAfQZAcUUN0iadUi8B/KOtpP75h/7G9fHrEqkCp99sgg7wavX1puf7R4dmCvgRlBoL/xhhw7asiHVjlaXWVoVAZSP2FQlNTfwpniFPhlKNNi4l1I1GkNSMQ6FuDpmxfSi1LEKlbgmaFvhubhlWATSROcC8bgBhwFZIul6gMOAyMmMfQ2nMZ6gM0GIJyjdOex6cw6oLYypYQPYHm1OnTbMov/yJZmhSjos92hfZ2TBEfphOP7BDHmKBG00sokEztXAHl2HTEPRMFebilyJ9EgS66J38nNqZcsFQSqACyPwBK0c62ukuVObnn5AxaKS4oqXM+YWYY/sHEV/YAPlQdI1aLmWwMzJiQmg8SWOkBe7QhhojQUBfPKqCcsJXdoj1EgHqpJsq/OlV7V3uAQDRD2BGaWOdz+aEmtOZuy2tE+K/Splp8grL3B3DQUPWoMfWlLI95LwWO5nNAA==") format("woff2"),url(/font/2bb59db229.woff) format("woff"),url(/font/a04a06a7d9.ttf) format("truetype"),url(/font/086b7e8295.svg#iconfont) format("svg")}.iconfont{font-family:iconfont!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-dollar:before{content:"\e6f4"}.icon-history:before{content:"\e6f8"}.icon-arrow-down:before{content:"\e665"}.icon-arrow-double-right:before{content:"\e666"}.icon-comment:before{content:"\e668"}
复制代码
13 js语法检查(eslint、airbnb)
统一团队代码风格,保证代码可读性
npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D
webpack.config.js
rules: [
...
{
/*
语法检查:eslint-loader eslint
检查自己写的代码,第三方库不用检查
设置检查规则:
方式一:在package.json中eslintConfig中设置
"eslintConfig": {
"extends": "airbnb-base"
}
方式二:
根目录新建.eslintrc
{
"extends": "airbnb-base"
}
推荐使用规则:airbnb
airbnb在eslint使用:
1. eslint-config-airbnb 包含react风格
2. eslint-config-airbnb-base 用这个
eslint-config-airbnb-base
Our default export contains all of our ESLint rules, including ECMAScript 6+. It requires eslint and eslint-plugin-import.
*/
// npm i eslint eslint-loader eslint-config-airbnb-base eslint-plugin-import -D
test: /\.js$/,
loader: "eslint-loader",
exclude: /node_modules/,
options: {
// 自动修复
// fix: true
}
}
]
复制代码
package.json新增字段
"eslintConfig": {
"extends": "airbnb-base"
}
复制代码
或者根目录新建.eslintrc
{
"extends": "airbnb-base"
}
复制代码
执行 webpack,可以看到控制台报错
/Users/zhengxiuyue/Documents/github-workspace/study-webpack/src/main.js
30:15 error A space is required after ',' comma-spacing
34:1 warning Unexpected console statement no-console
✖ 2 problems (1 error, 1 warning)
1 error and 0 warnings potentially fixable with the `--fix` option.
复制代码
webpack.config.js配置自动修复
options: {
// 自动修复
fix: true
}
复制代码
在次执行,js文件中已修复不符合代码,无报错,如下图
/Users/zhengxiuyue/Documents/github-workspace/study-webpack/src/main.js
34:1 warning Unexpected console statement no-console
✖ 1 problem (0 errors, 1 warning)
复制代码
如果想要无warning,可以在main.js加入eslint-disable-next-line
14 js兼容性处理(babel)
转成es5,支持浏览器运行
npm i babel-loader @babel/core -D
总结:结合1、3做兼容性处理
- 基本js兼容性处理 --> @babel/preset-env
npm i @babel/preset-env -S
问题:只能转换基本语法,如promise高级语法不能转换 - 全部js兼容性处理 --> @babel/polyfill
npm i @babel/polyfill -S
问题:我只要解决部分兼容性问题,但是将所有的兼容性代码全部引入,体积太大了 - 高级语法,需要做兼容性处理的就:按需加载 --> core-js
npm i core-js -S
操作步骤:
main.js写入es6语法,ie浏览器会报错
const add = (x, y) => x + y;
console.log(add(3, 9));
复制代码
webpack.config.js,或者在.babelrc babel.config.json 中配置
rules: [
...
{
/*
js兼容性处理:babel-loader @babel/core @babel/preset-env
npm i babel-loader @babel/core -D
1. 基本js兼容性处理 --> @babel/preset-env
npm i @babel/preset-env -S
问题:只能转换基本语法,如promise高级语法不能转换
2. 全部js兼容性处理 --> @babel/polyfill
npm i @babel/polyfill -S
问题:我只要解决部分兼容性问题,但是将所有的兼容性代码全部引入,体积太大了
3. 高级语法,需要做兼容性处理的就:按需加载 --> core-js
npm i core-js -S
结合1、3做兼容性处理
*/
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: { // 或者在.babelrc babel.config.json 中配置
// 预设,指定babel做这样的兼容性处理
presets: [
[
'@babel/preset-env',
{
// 按需加载
useBuiltIns: 'usage',
// 按需加载的内容
corejs: {
version: 3, // 制定版本
},
// 指定兼容性做到哪个版本
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17',
},
},
],
],
},
},
]
复制代码
执行webpack,可以看到打包后的main.js
const变成了var,箭头函数变成了普通函数,ie浏览器可以正常执行
eval("var add = function add(x, y) {\n return x + y;\n};\n\nconsole.log(add(3, 9));\n\n//# sourceURL=webpack://study-webpack/./src/main.js?");
复制代码
main.js写入promise,ie浏览器会报错,因为**@babel/preset-env**处理不了高级语法
const promise = new Promise((resolve) => {
setTimeout(() => {
console.log('定时器执行完了~');
resolve();
}, 1000);
});
console.log(promise);
复制代码
引入@babel/polyfill,在main.js中写入
import '@babel/polyfill';
复制代码
执行webpack,ie浏览器可以正常执行,但是打包后的main.js引入了js全部的高级语法处理,如下图,导致打包后的main.js文件体积很大
15 压缩html和js
压缩js
将mode调为production即可
mode="production" //压缩js,生产环境自动压缩js代码,会启用自带的UglifyJsPlugin
复制代码
压缩html
HtmlWebpackPlugin配置minify参数
plugins: [
new HtmlWebpackPlugin({
// 复制'./src/index.html'文件,并自动引入打包输出的所有资源(js/css)
template: './src/index.html',
// 压缩html
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true,
},
}),
],
复制代码
执行webpack,可以看到打包后的html被压缩了,且没有注释
16 回顾:生产环境的基本配置
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-lodaer',
{
// 在package.jso配置browserslist
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [['postcss-preset-env']],
},
},
},
];
module.exports = {
mode: 'production',
entry: './src/main.js',
output: {
filename: 'main.js',
path: path.join(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader],
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-lodaer'],
},
// 正常来讲,一个文件只能被一个loader处理,那么一定要指定loader执行的先后顺序
// 先执行eslint,在执行babel
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
enforce: 'pre', // 指定先后顺序,先执行
options: {
fix: true,
},
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBulitIns: 'usage',
corejs: {
version: 3,
},
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17',
},
},
],
],
},
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false, // html中用的是common, url-loader中用的是es6,需要关掉
},
},
{
test: /\.html/,
loader: 'html-loader', // 处理html中的img
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-lodaer',
options: {
outputPath: 'media',
},
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/main.css',
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true,
},
}),
],
};
复制代码
已同步语雀:www.yuque.com/go/doc/5319…
github:www.yuque.com/go/doc/5319…
本系列为Webpack——入门篇,包括:
1、Webpack——【入门篇-上篇】juejin.cn/post/695439…
2、Webpack——【入门篇-中篇】【本篇】juejin.cn/post/695438…
3、Webpack——【入门篇-下篇】juejin.cn/post/695438…