前端进阶 - webpack
前言
- 已经对
Vue/React/Angular等框架基本用法熟练掌握了? - 想进阶
webpack,却面对官网晦涩冗长的文字难以下手? - 每天高强度使用的
npm run dev, 却不知道其背后的含义? - 面试遇到
webpack总是面露难色?
我将会用最简洁的字符, 帮助你进阶webpack 。
笔者意在抛砖引玉,更多api及其细致特性请移步webpack官网翻阅。
阅读本文之前,你需要
- 掌握
JSCSSHTML - 掌握
ES6常用语法 - 完成
webpack官网 起步demo
本地环境
node v14+
webpack v5+
为什么要构建和打包(本文用webpack)?
代码层面:
- 打包出来的代码,体积更小( 通过
webpack过滤无用代码,压缩,合并等操作 ) - 支持高级语言语法,提升开发效率( 通过
webpack把TS,ES6+,scss等转译成绝大部分浏览器支持的语言 ) - 编译前或编译时,提示代码错误(
eslint等帮你校验代码 )
业务层面:
- 统一开发环境( 分成 dev [ test, gray, ... ] prod 环境去开发,高效 )
- 统一产出标准( 所有人产出的代码均转译成高兼容性的标准,稳定 )
- 统一构建规范( 把代码构建到指定目录,便捷 )
基本配置
拆分配置
使用: webpack-merge
作用: 通过抽离不同环境下的共同配置,来消除重复代码,提高开发效率
开发环境走 common & dev 的配置
生产环境走 common & prod 的配置
webpack-demo
├─ config
│ ├─ webpack.common.js // 存放公共的配置
│ ├─ webpack.dev.js // 存放开发环境的配置
│ ├─ webpack.prod.js // 存放生成环境的配置
├─ dist
├─ src
│ ├─ index.js // 入口文件
├─ package.json
config/webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
entry: path.join(__dirname, '..', 'src', 'index'),
plugins: [new HtmlWebpackPlugin()],
};
config/webpack.dev.js
const webpackCommonConf = require('./webpack.common.js')
const { merge } = require('webpack-merge')
module.exports = merge(
webpackCommonConf, // 融进 common 配置
{
mode: 'development',
devServer: {
port: 10086,
}
}
)
config/webpack.prod.js
const webpackCommonConf = require('./webpack.common.js')
const { merge } = require('webpack-merge')
const path = require('path')
module.exports = merge(
webpackCommonConf, // 融进 common 配置
{
mode: 'production',
output: {
filename: 'main.js',
path: path.resolve(__dirname, '..', 'dist'),
},
}
)
src/index.js
function component() {
const element = document.createElement('div');
element.innerHTML = 'hello webapck'
return element;
}
document.body.appendChild(component());
package.json
{
"name": "webpack-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"dev": "webpack serve --config config/webpack.dev.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0"
}
}
babel配置
使用: babel-loader
webpack官网声明:“兄弟们,babel-loader与我无关,它由社区维护,安全性我不保证嗷。”
作用: ECMAScript 2015+ => 老版浏览器能看懂的js代码
比如用例中的箭头函数,在babel-loader的转义前后的区别
src/index.js
/**
* Babel is a toolchain that
* is mainly used to convert ECMAScript 2015+ code
* into a backwards compatible version of JavaScript
* in current and older browsers or environments.
*
* ECMAScript 2015+ => 老版浏览器能看懂的js代码
*/
/**
* Babel Input: ES2015 arrow function
* Babel 转义 箭头函数
*/
[1, 2, 3].map(n => n + 1);
- 使用 babel-loader
dist/main.js
[1,2,3].map((function(n){return n+1}));
- 不使用 babel-loader
dist/main.js
[1,2,3].map((a=>a+1));
webpack-demo
├─ config-no-babel
│ ├─ webpack.common.js // 没用 babel-loader
│ ├─ webpack.dev.js
│ ├─ webpack.prod.js
├─ config
│ ├─ webpack.common.js // 用了 babel-loader
│ ├─ webpack.dev.js
│ ├─ webpack.prod.js
├─ dist
├─ src
│ ├─ index.js
├─ package.json
config/webpack.common.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
entry: path.join(__dirname, '..', 'src', 'index'),
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
/**
* You can also speed up babel-loader by
* as much as 2x by using the cacheDirectory option.
* This will cache transformations to the filesystem.
*
* 官方建议打开,可以缓存转义文件,提高2倍编译速度
*/
cacheDirectory: true
}
},
/* 转义 src 目录 */
include: path.join(__dirname, '..', 'src', 'index'),
/* 不转义 node_modules 目录 */
exclude: /node_modules/,
}
],
},
plugins: [new HtmlWebpackPlugin()],
};
package.json
{
...
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"build:with-no-babel": "webpack --config config-no-babel/webpack.prod.js",
"dev": "webpack serve --config config/webpack.dev.js"
},
...
"devDependencies": {
...
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.19.4",
"babel-loader": "^8.2.5"
}
}
可以使用
npm run build来打包使用babe-loader的配置可以使用
npm run build:with-no-babel来打包不使用babel-loader的配置
抽离 & 压缩 css文件
使用: MiniCssExtractPlugin
作用: 分离压缩,按需加载。
This plugin extracts CSS into separate files. It creates a CSS file per JS file which contains CSS. It supports On-Demand-Loading of CSS and SourceMaps.
示例代码供比较,分离压缩前后,打包文件的区别
- 使用
MiniCssExtractPlugin
├─ dist
│ ├─ index.html
│ ├─ main.js
│ ├─ main.css // 直接插到 html 文件中
- 不使用
MiniCssExtractPlugin
├─ dist
│ ├─ index.html
│ ├─ main.js // css文件通过 style-loader 转义,插入到 js 文件中
webpack-demo
├─ config-without-miniCssExtractPlugin
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ ├─ webpack.prod.js // 没用 MiniCssExtractPlugin
├─ config
│ ├─ webpack.common.js
│ ├─ webpack.dev.js
│ ├─ webpack.prod.js // 用了 MiniCssExtractPlugin
├─ dist
├─ src
│ ├─ style.css
│ ├─ index.js
├─ package.json
config/webpack.prod.js
const webpackCommonConf = require('./webpack.common.js')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { merge } = require('webpack-merge')
const path = require('path')
module.exports = merge(
webpackCommonConf,
{
mode: 'production',
output: {
filename: 'main.js',
path: path.resolve(__dirname, '..', 'dist'),
},
plugins: [
new MiniCssExtractPlugin()
],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
}
}
)
config-without-miniCssExtractPlugin/webpack.prod.js
const webpackCommonConf = require('./webpack.common.js')
const { merge } = require('webpack-merge')
const path = require('path')
module.exports = merge(
webpackCommonConf,
{
mode: 'production',
output: {
filename: 'main.js',
path: path.resolve(__dirname, '..', 'dist'),
},
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
}
}
)
src/style.css
body{
background: #ccc;
}
src/index.js
import "./style.css";
package.json
{
...
"scripts": {
"build": "webpack --config config/webpack.prod.js",
"build:with-no-css-mini": "webpack --config config-without-miniCssExtractPlugin/webpack.prod.js",
"dev": "webpack serve --config config/webpack.dev.js"
},
...
"devDependencies": {
...
"style-loader": "^3.3.1",
"css-loader": "^6.7.1",
"mini-css-extract-plugin": "^2.6.1",
}
}
可以使用
npm run build来打包使用mini-css-extract-plugin的配置可以使用
npm run build:with-no-css-mini来打包不使用mini-css-extract-plugin的配置
未完待续...