什么是Webpack?
webpack 是一个JavaScript程序静态模块打包工具,当webpack处理程序时,会递归构建一个依赖关系图,对程序需要的每个模块进行编译、压缩、打包等,可打包成一个文件或多个文件。
webpack 的核心概念
其中 entry、output、loader和plugins 是 webpack 的四个核心概念
- entry(入口)
- output(输出)
- loader
- plugins(插件)
- mode(模式)
- module(模块)
- chunk
1. entry
入口起点,是指在 webpack 中应该使用哪个模块,来作为构建内部依赖的开始,webpack 会找出哪些模块是根据入口起点的文件依赖的。
每个依赖的模块经过处理后,最终都将打包到名叫 buildle 文件中。
在webpack中设置entry属性指定一个入口起点或多个入口起点。
webpack.config.js
module.exports = {
entry: "./src/index.js"
}
2. output
output属性是告诉 webpack 在哪里输出我们创建的 buildle 文件,以及如何命名这些文件和设置这些文件的所在路径。
webpack.config.js
let path = reuqire("path");
module.exports = {
outpur:{
path:path.resolve(__dirname,"dist"),
filename:"build.js"
}
}
output.path和output.filename 分别指定输出文件的路径,和输出文件的名称
3. loader
lodaer 可以理解为模块转换器,loader 可以将所有模块内容转为所需的内容,然后在利用 webpack 打包功能,对他们进行处理。
webpack.config.js
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:['css-loader']
}
]
}
}
在module对象中的rules属性必须有包含test和use属性,这将告诉 webpack 在以.css结尾的文件打包时,先使用css-loader对他进行转换。
4. plugins
loader 被用于转换模块,而 plugins 用于更加广泛的范围,webpack 提供了丰富的插件解决,基于这些接口我们可以做到任何想做的事情。
webpack.config.js
let webpack = require("webpack"); //适用于 webpack 提供的内部插件
let HtmlWebpackPlugin = require("html-webpack-plugin"); //外部插件,基于 npm 安装
module.exports = {
plugins:[
new HtmlWebpackPlugin() //使用插件
]
}
5. mode
可选择development(开发模式)和production(生产模式)中一个来设置mode的值。
webpack.config.js
module.exports = {
mode: 'production'
};
6. module
在 webpack 中一切皆是模块,每一个模块都对应一个文件,webpack 会从 entry 开始递归找出所有依赖的模块。
7. chunk
代码块,一个 chunk 由多个模块组成,用于代码的分割与合并。
配置 webpack
webpack 的配置文件叫做webpack.config.js。是一个导出对象javascript文件。
webpack 配置是标准的Node.js CommonJS模块。在 webpack 配置文件中,采用require导入文件。
1. 初始化
1.1 创建 & 初始化项目
mkdir webpack-demo && cd webpack-demo && npm init -y
1.2 安装 webpack, D 是局部安装
npm install webpack webpack-cli -D
1.3创建 src 和 dist 目标
mkdir src && mkdir dist
创建 src 目录下的index.js
touch index.js
2 配置 webpack
2.1 配置webpack 文件
mkdir webpack.config.js
2.2 配置 webpack.config.js
let path = path.require("path");
module.exports = {
entry:"./src/index.js",
output:{
path:path.resolve(__dirname,"dist"),
filename:"build.js"
}
}
entry 属性的配置可以是多个入口
cd src && mkdir b.js
module.exports = {
entry:{
A:"./src/index.js",
B:"./src/b.js"
},
output:{
path:path.resolve(__dirname,"dist"),
filename:"[name]"
}
}
多个入口的情况下,output.filename属性值改为"[name]",这样输出的文件名和entry设置的入口文件名一一对应。
2.3 在 src 目录创建 index.html 文件
touch index.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div> 世界,你好</div>
</body>
</html>
2.4 配置 package.json 文件,可以使我们在命令行使用npm run build
"scripts":{
"build":"webpack"
}
2.5 配置mode
webpack 的 mode 配置用于提供配置选项告诉 webpack 相应的使用其内置的优化,mode 有三个值:development、production和none。
{
module.exports = {
mode: "development"
}
}
3 配置开发服务器
3.1 安装依赖
npm install webpack-dev-server -D
3.2 配置 package.json 文件,便于我们在命令行输入npm run dev
"scripts":{
"dev": "webpack-dev-server"
}
3.3 配置webpack.config.js文件
let path = require("path");
module.exports = {
devServer:{
contentBase: path.resolve(__dirname,"dist"),
host:"localhost",
port:"3000",
compress:true, // 是否 gzip 压缩
open: true // 是否自动打开浏览器窗口
}
}
4 支持加载 css 文件
- css-loader
- style-loader
4.1 安装 loader
npm install css-loader style-loader -D
loader 执行顺序是从右到左,从上到下
4.2 配置webpack.config.js文件
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:["style-loader","css-loader"] // use属性值可以是 []、string和对象
}
]
}
}
4.3 配置html-webpack-plugin插件并导入到webpack.config.js文件
html-webpack-plugin 简化了 HTML 文件的创建,并且能够自动产出一个 HTML 文件,并且在里面引入产出后的资源。详情请移步 npmjs 了解。
npm install html-webpack-plugin -D
let HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
plugins: [
// 如果有多个 HTML 文件 HtmlWebpackPlugin 执行多次
new HtmlWebpackPlugin({
template: "./src/index.html", // 模板的文件路径
filename:"main.html", // 将要写入在 HTML 中的文件名,默认是index.html
chunks:["A"],
hash:true, // 在产出的资源后面添加哈希值,以避免缓存
minify:true, //是否对HTML压缩,默认是true
})
]
}
5 css 分离
因为 css 的下载和 js 可以一起运行,所以当一个 HTMl 很大时,我们可以把 css 分离单独的文件。
5.1 安装依赖模块
npm install mini-css-extract-plugin -D
这个插件可以 css 提取到单独是文件中。支持按需加载 css 和 SourceMaps。此插件在 webpack 4上使用。
5.2 配置webpack-config.js文件
let MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module:{
rules:[
{
test:/\.css$/,
use:[MiniCssExtractPlugin.loader,"css-loader"]
//该插件自带一个loader 用来处理css变成css文件形式的
}
]
},
plugins:[
new MiniCssExtractPlugin({
filename:"style.css"//css 文件名
})
]
}
5.3 压缩 JS 和 CSS
因为使用了 css 分离的插件mini-css-extract-plugin,所以这时代码不在自动压缩,需要我们手动压缩代码。
5.3.1 压缩 CSS
安装依赖
npm install optimize-css-assets-webpack-plugin -D
配置webpack.config.js文件
let OptimizeCss = require("optimize-css-assets-webpack-plugin");
module.exports = {
plugins: [
new OptimizeCss()
]
}
5.3.2 压缩 JS
安装依赖
npm install uglifyjs-webpack-plugin -D
配置webpack.config.js文件
let UglijsWebpackPligin = require("uglifyjs-webpack-plugin");
module.exports = {
plugins:[
new UglijsWebpackPligin({
cache: true,
parallel: true,// 并行,多进程快速构建打包
sourceMap: true // 映射代码源
})
]
}
除了uglifyjs-webpack-plugin之外也可以使用terser-webpack-plugin。
5.4 less 和 sass
安装依赖
npm install less less-loader -D
npm install node-sass sass-loader -D
配置webpack.config.js文件
let path = require("path");
let MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module:{
rules:[
{
test:/\.less$/,
exclude:/node_modules/, // 排除 node_modules
include: path.resolve(__dirname,"src"), // 选中范围
use:[MiniCssExtractPlugin.loader,"css-loader","less-loader"]
},
{
test:/\.scss$/,
exclude:/node_modules/,
include: path.resolve(__dirname,"src"),
use:[MiniCssExtractPlugin.loader,"css-loader","sass-loader"]
}
]
}
}
5.5 添加 CSS3 属性前缀
有时候为了处理兼容性问题,我们需要在 css 中加入-webkit,-ms,-o,-moz 这些前缀。
- Trident内核:主要代表为IE浏览器, 前缀为-ms
- Gecko内核:主要代表为Firefox, 前缀为-moz
- Presto内核:主要代表为Opera, 前缀为-o
- Webkit内核:产要代表为Chrome和Safari, 前缀为-webkit
安装依赖
npm install postcss-loader autoprefixer -D
配置webpack.config.js文件
module.exports = {
module:{
rules:[
{
test:/\.scss$/,
exclude:/node_modules/,
use:[MiniCssExtractPlugin.loader,"css-loader","postcss-loader","sass-loader"]
}
]
}
}
还需要新建一个postcss.config.js配置文件并配置
touch postcss.config.js
module.exports = {
plugins:[
require("autoprefixer")
]
}
6 支持图片
引入图片的三种方式
- js
- css
- html
6.1 安装依赖
npm install file-loader url-loader -D
6.2 配置webpack.config.js文件
module.exports = {
module:{
rules:[
{
test:/\.(png|jpe?g|fig)/,
use:{
loader:"url-loader",
options:{
limit:200*2024
}
}
}
]
}
}
file-loader和url-loader的区别是url-loader的limit属性可设置一个参数。
limit 值在限制大小之内采用 base64,超过采用file-loader
6.3 安装 HTML 中可用图片依赖
npm install html-withing-loader -D
配置webpack.config.js文件
module.exports = {
module: {
rules:[
{
test:/\.html$/,
loader: "html-withing-loader"
}
]
}
}
7 转义 ES6/7/JSX
Babel是一个可以编译 JavaScript 的平台,能够把 ES6/7/JSX 编译成 ES5。
7.1 安装依赖
npm install babel-loader @babel/core @babel/preset-env -D
7.2 配置webpack.config.js文件
modules.exports = {
module:{
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
use:{
loader: "babel-loader",
options: {
presets: ["@label/preset-env"], // ES6 转成ES5 模块
}
}
}
]
}
}
此外,还有分别转换装饰器和类的babel包@babel/plugin-proposal-decorators&@babel/plugin-proposal-class-properties。
7.3 @babel/plugin-transform-runtime 插件 从 ES6 编译 ES5 的过程中,有一些是不被应用的。例如
给index.js添加 Generator 函数
function *fn(){
yield "哈哈哈..."
}
console.log(fn().next());
会在浏览器控制台报错,提示regeneratorRuntime方法找不到。因为此时在编译后的 js 文件中,没有regeneratorRuntime的由来,只有使用。
index.js:8 Uncaught ReferenceError: regeneratorRuntime is not defined
@babel/plugin-transform-runtime 就是起到帮助代码填充在转义过程中一些不存在的代码。该插件在使用时,还需依赖@babel/runtime。
7.4 安装依赖
npm install @babel/plugin-transform-runtime @babel/runtime -D
7.5 配置webpack.config.js文件
module.exprots = {
module:{
rules:[
{
test:/\.js$/,
exclude:/node_modules/,
use:[{
loader:"babel-loader",
options:{
presets:["@babel/preset-env"],
plugins:["@babel/plugin-transform-runtime"]
}
}]
}
]
}
}
7.6 @babel/polyfill 插件
因为@babel/plugin-transform-runtime并不能解决类似"foobar".includes("foo")实例上的这种问题。如果需要polyfill可使用@babel/polyfill。
安装依赖
npm install @babel/polyfill -D
修改index.js文件,可直接在文件里导入@babel/polyfill使用
import "@babel/polyfill";
'aaa'.includes('a');
8 调式代码
sourcemap是帮助我们解决开发代码和实际运行不一致时帮助我们debug到原始代码
8.1 配置webpack.config.js
module.exports={
devtool: "source-map" // 代码映射,可直接找到源代码的行列位置
}
source-map会单独打包成一个.map的文件和原始代码相关联。cheap-module-eval-source-map 则不会打包.map文件,而是直接在打包文件的内部进行相关联,不能准确的定位到列数。有关其他详细参数可到 webpack
9 监听打包
webpack 可以监听文件变化,当修改文件内容后会重新编译。启动watch模式,意味着在构建之后, webpack 将继续监听任何文件的更改。watchOpions可以配置一些监听打包规则
9.1 配置webpack.config.js
module.exports={
watch:true,
watchOpions:{ // 监听打包配置选项
poll:1000, // 以秒为单位,每1秒检查检查一次
ignored:{ // 排除 node_modules 文件夹
test:/node_modules/
}
}
}
10 打包前清除打包目录
10.1 安装依赖
npm install clean-wbpack-plugin
10.2 配置webpack.config.js
let CleanWebpackPlugin = require("clean-webpack-plugin");
module.exports={
plugins:[
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns:["./dist"]
})
]
}
11 复制文件
11.1 安装依赖
npm install copy-webpack-plugin
11.2 配置webpack.config.js
let CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports ={
plugins:[
new CopyWebpackPlugin([
{from:"./src/test.js",to:path.resolve(__dirname,"dist")}
])
]
}
11.3 目录展示

12 为打包文件添加注释
BannerPlugin是 webpack 自带的一个插件,能够给打包后的文件添加一些注释之类的信息。
12.1 配置webpack.config.js
let webpack = require("webpack");
module.exports = {
plugins:[
new webpack.BannerPlugin("你好")
]
}
12.2 展示

13 解析第三方文件
想在 js 文件中引入一个style.css,写的时候想忽略.css格式或者忘记写的时候,那么解析就会报错。因为默认这样引入import style的是一个 js 文件,而不是我们想要的 css 文件。resolve`属性可以帮助我们的解决这个问题。
13.1 配置webpack.config.js
let path = require("path");
module.exports={
resolve:{
modules:[path.resolve("node_modules")],// 指定搜索目录,可以是多个目录。在引入的外部 css 文件,node_modeuls 找不到则会继续往上找到
ailas:{ // 起个别名
"style":"./src/style.css"
},
extensions:[".js",".json",".css"] // 自动解析设置的扩展名,默认 .js .json
}
}
14 服务器代理
希望前后端在同一个域名下发送 API 请求时,那么代理某些 URL 是很有必要的
14.1 配置一个server文件
安装依赖
npm install express -D
let express = require("express");
let app = express();
app.get("/api/user",async (req,res)=>{
res.json({name: "哈哈"})
})
app.listen(3000)
14.2 配置webpack.config.js
module.exports={
devServer:{
proxy:{
"/api":"http://localhost:3000"
}
},
}
14.3 自己 mock 数据
配置webpack.config.js
module.exports={
devServer:{ // 可以自己造假数据
before(app){// 默认 webpack-dev-server 启动的时候会调用这样的一个钩子函数,app 是我们的 express()
app.get('/api/user',(req,res)=>{
res.json({name:"xm"})
})
}
},
}
15 分离代码块
weboack 3 还需要commonChunklsPligin插件,在webpack 4就没有了,这里以 4 为准
module.exports={
optimization:{
splitChunks:{ //分离代码模块
cacheGroups:{ // 缓存组
common:{
chunks:"initial",
minSize:0, // 只要公用的部分超过0个字节 就抽离出来
minChunks:2 // 至少引用2次才抽离
},
vendor:{ //抽离第三方插件的
priority:1, // 权重 先执行,为了避免在 common 这里把所有的文件都抽离出来 默认是0
test:/node_modules/,
chunks:"initial",
minSize:0,
minChunks:2
}
}
}
}
}
16 热更新
react-hot-loader只更新修改的部分
16.1 安装依赖
npm install react-hot-loader
16.2 配置.babelrc
{
"plugins":["react-hot-loader/babel"]
}
配置webpack.config.js
module.exports={
module:{
rules:[
{
test:/\.js$/,
use:[{
loader:"babel-loader",
options:{
presets:["@babel/preset-env","@babel/preset-react"] // 预设react
}
}]
},
{
test:/\.css$/,
loader:["style-loader","css-loader"]
}
]
},
}
16.3 修改文件
home.js
import * as React from "react";
import 'react-hot-loader';
import { hot } from 'react-hot-loader/root';
class App extends React.Component{
render(){
return <div>Hello111 World!<input type="text"/></div>;
}
}
export default hot(App);
修改 index.js
import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./home";
ReactDOM.render(<App/>, document.getElementById('root'));
基本的配置到此就结束了。
有任何问题欢迎指出。有其他详情请移步npm & babel & 中文webpack官网
都看到这里给点个赞呗 ^_^ ~