实践后加深的理解
- 开发环境(devlopment):能让代码本地调试运行的环境。
- 生产环境(production):能让代码优化上线运行的环境。
- 生产环境包的构建:为了让代码能在生产环境表现的更加优秀,构建时除需要关注代码普通的编译打包功能之外,还需要关注代码的浏览器兼容以及运行速度等相关问题。
实践结果
package.json
{
"name": "webpack_dep_test",
"version": "1.0.0",
"devDependencies": {
"@babel/core": "^7.8.7",
"@babel/preset-env": "^7.8.7",
"babel-loader": "^8.0.6",
"core-js": "^3.6.4",
"css-loader": "^3.4.2",
"eslint": "^6.8.0",
"eslint-config-airbnb-base": "^14.1.0",
"eslint-loader": "^3.0.3",
"eslint-plugin-import": "^2.20.1",
"file-loader": "^5.1.0",
"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",
"url-loader": "^3.0.0",
"webpack": "^4.42.0",
"webpack-cli": "^3.3.11"
},
"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
}
}
}
webpack.config.js
const {
resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
process.env.NODE_ENV = 'development';
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
entry:"./src/js/entry.js",
output:{
path:resolve(__dirname,'build'),
filename:'js/built.js'
},
module:{
rules:[
{
test:/\.less$/,
use:[MiniCssExtractPlugin.loader,'css-loader',{
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
},'less-loader']
},
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader',{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}]
},
{
// 检查工具:eslint-loader、eslint
// 检查目标:除node_module下的所有js文件。
// 检查规则:在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre',// 和babel-loader都处理js文件,而eslint关注的是src而不是build,优先执行
loader: 'eslint-loader',
options: {
fix: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',// 按需加载
corejs: {
version: 3// 指定core-js版本
},
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]',
esModule:false,
outputPath: 'images'
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
collapseWhitespace: true,// 移除空格
removeComments: true// 移除注释
}
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin()
],
// 生产环境下会自动压缩js代码
mode: 'production'
};
实践准备
创建项目:webpack_dep_test
初始化
npm init
npm i webpack webpack-cli -D
// 上篇博客编译打包功能涉及到的所有依赖
npm i css-loader file-loader html-loader html-webpack-plugin less less-loader style-loader url-loader -D
- src/js/entry.js:空文件
- webpack.config.js:复制上篇博客产生的webpack.config.js文件
const {
resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry:"./src/js/entry.js",
output:{
path:resolve(__dirname,'build'),
filename:'js/built.js'
},
module:{
rules:[
{
test:/\.less$/,
use:['style-loader','css-loader','less-loader']
},
{
test:/\.css$/,
use:['style-loader','css-loader']
},
{
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
esModule:false,
outputPath: 'images'
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins:[
new HtmlWebpackPlugin({
template:'./src/index.html'
})
],
mode:'development'
};
实践过程
一:css提取
1.优化目标
- 将所有样式文件从built.js提取出来得到一个bundle,以减小built.js的体积。
- build/index.html中head标签内link外部的css bundle,而body标签内script外部built.js。
2.操作示例
- 打包前
- plugin:mini-css-extract-plugin插件的下载、引入、配置
npm i mini-css-extract-plugin -D
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
...
plugins:[
...,
new MiniCssExtractPlugin({
filename: 'css/built.css'// 提取css后输出文件的位置
})
...
]
...
- loader:MiniCssExtractPlugin.loader的配置
使用MiniCssExtractPlugin.loader替换style-loader,css生效方式由内嵌式(head下style标签内容)变为外部式(head下link标签引入)
...
module:{
rules:[
{
test:/\.less$/,
use:[MiniCssExtractPlugin.loader,'css-loader','less-loader']
},
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader']
},
...
]
}
...
- 打包后
entry.js中引入的所有css、less文件都被打包进built.css文件之中。
二:css兼容
1.优化目标
- 让css兼容更多的浏览器。
2.操作示例
- 打包前:src/css/test.css
#box1 {
width: 100px;
height: 100px;
background-color: pink;
display: flex;
backface-visibility: hidden;
}
- loader:postcss-loader的下载、配置
// postcss-preset-env插件:帮postcss找到package.json中browserslist里面的配置,通过配置加载指定的css兼容性样式
npm i postcss-loader postcss-preset-env -D
// 设置nodejs的运行环境(让postcss-preset-env插件加载对应环境的配置)
process.env.NODE_ENV = 'development';
...
module:{
rules:[
{
test:/\.less$/,
use:[MiniCssExtractPlugin.loader,'css-loader',{
// 在css-loader加载之前使用postcss加载
// 还需要在package.json中定义browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
},'less-loader']
},
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,'css-loader',{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}]
},
...
]
}
- package.json:配置browserslist(不同环境时需要兼容的浏览器列表)
{
...,
"browserslist": {
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
}
- 打包后:build/css/built.css(entry.js只引入了test.css一个css文件)
#box1 {
width: 100px;
height: 100px;
background-color: pink;
display: flex;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
三:css压缩
1.优化目标
- 压缩以减小css文件体积,加快下载速度。
2.操作示例
- 打包压缩前:test.css
#box1 {
width: 100px;
height: 100px;
background-color: pink;
display: flex;
backface-visibility: hidden;
}
- plugin:optimize-css-assets-webpack-plugin的下载、引入、配置
npm i optimize-css-assets-webpack-plugin -D
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
...
plugins:[
...,
new OptimizeCssAssetsWebpackPlugin()
]
...
- 打包压缩后:build/css/built.css(entry.js只引入了test.css一个css文件)
#box1{
width:100px;height:100px;background-color:pink;display:flex;-webkit-backface-visibility:hidden;backface-visibility:hidden}
四:js检查(语法)
1.优化目标
- 打包的同时,风格化代码。
2.操作示例
- 打包前:src/js/test.js(被entry.js引入)与src/js/test2.js(不被entry.js引入)
// 被entry.js引入的test.js
function test(a,b) {
a+= 1;
return a+b
}
console.log(test(3,5))
// 与test.js文件内容一致但未被entry.js引入的test2.js
function test(a,b) {
a+= 1;
return a+b
}
console.log(test(3,5))
- loader:eslint-loder的下载、配置
// 检查工具:eslint及其loader
npm i eslint-loader eslint -D
// 检查规则:airbnb风格,eslint-config-airbnb-base eslint-plugin-import
npm i eslint-config-airbnb-base eslint-plugin-import -D
module:{
rules:[
...,
{
// 检查工具:eslint-loader、eslint
// 检查目标:除node_module下的所有js文件。
// 检查规则:在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
enforce: 'pre',// 和babel-loader都处理js文件,而eslint关注的是src而不是build,优先执行
loader: 'eslint-loader',
options: {
fix: true //自动修复
}
},
...
]
}
- package.json
{
...,
"eslintConfig": {
"extends": "airbnb-base",
"env": {
"browser": true
}
}
- 打包信息
- 打包后:src/js/test.js(被entry.js引入)与src/js/test2.js(不被entry.js引入)
test.js被检查并自动修正,而test2.js没有。说明未被entry.js引入的js文件不会被eslint-loader加载,也就不会被eslint检查并自动修正。
// 被entry.js引入的test.js
function test(a, b) {
a += 1;
return a + b;
}
console.log(test(3, 5));
// 与test.js文件内容一致但未被entry.js引入的test2.js
function test(a,b) {
a+= 1;
return a+b
}
console.log(test(3,5))
五:js兼容
注意:生产环境才需要做兼容。
1.优化目标
- 做好js的代码兼容操作以兼容生产环境下多样的浏览器。
2.操作示例
- 打包前:src/js/test.js
// 箭头函数等基本语法可以被@babel/preset-env兼容,而Promise等高级语法不可以。
// Promise使用core-js库做兼容处理
let test = (a, b) =>{
a += 1;
return a + b;
};
let promise = new Promise(()=>{
setTimeout(()=>{
console.log(5)
},1000)
});
console.log(test(3, 5));
- loader:babel-loader的下载与配置
- 依赖核心库 -D:@babel/core
- 【选用】基本语法兼容库 -D:@babel/preset-env
- 【选用】部分js语法兼容库 -D(优点:按需加载):core-js
- 【弃用】全部js语法兼容库 -D(缺点:造成打包体积太大):@babel/ployfill
npm i babel-loader @babel/core @babel/preset-env core-js -D
module:{
rules:[
...,
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',// 按需加载
corejs: {
version: 3// 指定core-js版本
},
targets: {
// 指定兼容性做到哪个版本浏览器
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
},
...
]
}
- 打包后:build/js/built.js
(function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.object.to-string */ \"./node_modules/core-js/modules/es.object.to-string.js\");\n/* harmony import */ var core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_object_to_string__WEBPACK_IMPORTED_MODULE_0__);\n/* harmony import */ var core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! core-js/modules/es.promise */ \"./node_modules/core-js/modules/es.promise.js\");\n/* harmony import */ var core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_promise__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var core_js_modules_web_timers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! core-js/modules/web.timers */ \"./node_modules/core-js/modules/web.timers.js\");\n/* harmony import */ var core_js_modules_web_timers__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_web_timers__WEBPACK_IMPORTED_MODULE_2__);\n\n\n\n\nvar test = function test(a, b) {\n a += 1;\n return a + b;\n};\n\nvar promise = new Promise(function () {\n setTimeout(function () {\n console.log(5);\n }, 1000);\n});\nconsole.log(test(3, 5));\n\n//# sourceURL=webpack:///./src/js/test.js?");
/***/ })
/******/ });
六:js压缩
1.优化目标
- 压缩js代码,减小js文件的体积,以加快下载速度。
2.操作示例
- 未启用压缩前:build/js/built.js
- plugin:webpack内置插件
module.exports = {
...,
// 生产环境下会自动压缩js代码
mode: 'production'
}
- 启用压缩后:build/js/built.js
七:html压缩
1.优化目标
- 压缩html代码,以减小html的体积,加快下载速度。
2.操作示例
- 打包前:src/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>webpackDepTest</title>
</head>
<body>
<H1>webpack_dep_test template for src/index.html</H1>
</body>
</html>
- plugin:html-webpack-plugin的配置(已下载)
plugins:[
new HtmlWebpackPlugin({
template: './src/index.html',
// 压缩html代码
minify: {
collapseWhitespace: true,// 移除空格
removeComments: true// 移除注释
}
}),
...
]
- 打包后:build/index.html
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>webpackDepTest</title></head><body><h1>webpack_dep_test template for src/index.html</h1><script type="text/javascript" src="js/built.js"></script></body></html>