基本使用
1. 创建一个项目
创建一个空目录(不要使用webpack来命名)作为项目根目录,在命令行中执行以下命令来对项目进行初始化,生成 package.json
文件:
npm init -y
复制代码
2. 安装 webpack
全局安装(不推荐)
// 安装webpack 4x版本时,需要额外安装webpack-cli
// 不跟上版本号时,会安装最新的5.x版本
npm install webpack webpack-cli -g
// 检查版本
webpack -v
// 卸载
npm uninstall webpack webpack-cli -g
复制代码
全局安装webpack,这会将你项⽬中的webpack锁定到指定版本,造成不同的项⽬中因为webpack依赖不同版本⽽导致冲突,构建失败,所以不推荐。
局部安装(项目安装)
在项目中执行以下命令局部安装 webpack 相关工具webpack
和webpack-cli
,两者缺一不可。
// 安装最新的稳定版本
npm i webpack -D
// 安装指定版本
npm i webpack@<version> -D
// 安装最新的体验版本 可能包含bug,不要⽤于⽣产环境
npm i webpack@beta -D
// 安装webpack V4+版本时,需要额外安装webpack-cli
npm i webpack-cli -D
// 一次安装两个
npm i webpack@<version> webpack-cli -D
// 例如安装4.43.0版本: npm i webpack@4.43.0 webpack-cli -D
复制代码
检查安装
webpack -v // 默认在全局环境中查找
npx webpack -v// npx在项⽬中的node_modules⾥查找webpack
./node_modules/.bin/webpack -v//到当前的node_modules模块⾥查找webpack
复制代码
3. 执行 webpack进行构建
- webpack默认只⽀持JS模块和JSON模块
- ⽀持
commonJS
、es moudule
、AMD
等模块类型
3.1创建项目文件
- 在项目根目录中创建一个 src文件夹。
- src文件夹下新建
index.js
、a.json
、b.js
。
在三个文件中,依次写上:
### index.js
const json = require("./a.json");// commonJS
import { demo } from "./b.js";//es module
console.log(json, demo(5, 3));
### a.json
{
"name": "PYY"
}
### b.js
export function demo(x, y) {
return x - y;
}
复制代码
3.2 构建
方式1
可以通过以下命令,让 webpack 对项目代码进行转换:
npx webpack
复制代码
为什么需要使用npx呢?因为我们没有全局安装webpack,所以我们如果直接使用webpack命令,就会找不到。而npx 会在当前项目中,node-modules中bin目录去找到webpack软链接,然后启动它。
方式2
在 package.json
文件中的scripts中,添加命令
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack"
},
复制代码
然后在项目根目录执行命令:
npm run dev
复制代码
同样的也是去node-modules中bin目录去找到webpack软链接,然后启动它。
原理
原理就是通过shell脚本在node_modules/.bin⽬录下创建⼀个软链接。
4. 构建成功
我们会发现⽬录下多出⼀个 dist ⽬录,⾥⾯有个 main.js
,这个⽂件是⼀个可执⾏的JavaScript⽂件,⾥⾯包含webpackBootstrap
启动函数。
Hash: 本次经行构建的版本hash号码。
Version:本次打本webpack版本号
创建了main.js文件,文件的大小是948字节 chunks为0 chunk name为main
警告: mode选项没有设置,设置为production(生产模式) 或者development(开发模式),默认是production。
配置webpack
1.默认配置
webpack 默认只支持 JS、JSON 文件进行打包处理(其他两种用不上)。
webpack 的配置文件是项目根目录中的 webpack.config.js
文件,当我们执行打包命令 npx webpack
时,webpack会自动去查找 webpack.config.js
文件并使用其中的配置信息来进行打包,当我们没有手动创建 webpack.config.js
文件时,就会走默认配置。
const path = require("path");
module.exports = {
// 1.webpack执⾏构建的⼊⼝
entry: "./src/index.js",
// 2.webpack执⾏构建的出口
output: {
// 输出⽂件的存放路径,path必须是绝对路径
path: path.resolve(__dirname, "./dist"),
// 将所有依赖的模块合并输出到main.js,也就是说打包好的文件叫什么名字
filename: "main.js",
},
// 3.打包的模式
mode: "production", //打包模式,有三种:development开发模式、production生产模式、none不开启任何模式
};
复制代码
2.更改默认配置
当我们手动去创建 webpack.config.js
文件时,默认配置就会失效,就会走我们的 webpack.config.js
文件(不会合并)。
const path = require("path");
module.exports = {
// 1.webpack执⾏构建的⼊⼝
entry: "./src/index.js",
// 2.webpack执⾏构建的出口
output: {
// 输出⽂件的存放路径,path必须是绝对路径
path: path.resolve(__dirname, "./build"),
// 将所有依赖的模块合并输出到main.js,也就是说打包好的文件叫什么名字
filename: "dist.js",
},
// 3.打包的模式
mode: "production", //打包模式,分为两种:development开发模式、production生产模式
};
复制代码
3.自定义配置文件(不推荐)
使用 --config
来自定义配置。
在根目录下新建个config
文件夹,在文件夹中新建webpack.test.js
,写上代码:
const path = require("path");
module.exports = {
// 1.webpack执⾏构建的⼊⼝
entry: "./src/index.js",
// 2.webpack执⾏构建的出口
output: {
// 输出⽂件的存放路径,path必须是绝对路径
path: path.resolve(__dirname, "./build1"),
// 将所有依赖的模块合并输出到main.js,也就是说打包好的文件叫什么名字
filename: "dist1.js",
},
// 3.打包的模式
mode: "production", //打包模式,分为两种:development开发模式、production生产模式
};
复制代码
添加pageage.json中scripts中命令:"start": "webpack --config ./config/webpack.test.js",
根目录下执行npm run start
webpack的核心配置
entry
entry指定webpack打包的入口: Webpack 执⾏构建的第⼀步将从 entry 开始,可抽象成输⼊。
entry有3种类型: 字符串string、数组array、对象object。
-
entry: “./src/index.js”,
等同于: { “main”: “./src/index.js” }
注意: bundle:1个打包文件,里面包含了index.js的代码片段(chunks代码块)
-
entry: [“./src/b.js”, “./src/index.js”, “./src/a.json”], 注意:bundle:1个打包文件,包含了a.js片段 b.js片段,最终整合了这两个片段。
-
entry: { // key 对应的是输出的bundle文件名称 bundle: './src/index.js', // bundle入口 a: './src/a.json', // a入口 b: './src/b.js' // b入口 }, // 多入口需要对应多入口filename的值需要改成: "[name].js", [name]对应着key 占位符 bundle文件名称 复制代码
单入口: 字符串string、数组array
多入口: 对象object。
分析: a.json、b.js、index.js是模块(module),最终会得到代码块(chunk)。
index.js 模块(module) 处理后生成的代码片段叫 chunk index
a.json 模块(module) 处理后生成的代码片段叫 chunk a
b.js 模块(module) 处理后生成的代码片段叫 chunk b
chunk就是打包之后eval()里面的代码块
复制代码
mode entry output module chunks bundle之间的联系?
output
打包转换后的⽂件输出到磁盘位置:输出结果,在 Webpack 经过⼀系列处理并得出最终想要的代码后输
出结果。
output: {
filename: "bundle.js",//输出⽂件的名称
path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录(也就是写入到硬盘),必须是绝对路径
},
//多⼊⼝的处理
output: {
filename: "[name][chunkhash:8].js",//利⽤占位符,⽂件名称不要重复
path: path.resolve(__dirname, "dist")//输出⽂件到磁盘的⽬录,必须是绝对路径
},
output: {
filename: "js/[name][chunkhash:8].js",// 把js代码放入到js文件夹中
path: path.resolve(__dirname, "dist"),
publicPath: "存放JS⽂件的CDN地址", // 给输出资源文件中添加url(也就是cdn地址),就省得我们自己给静态资源加服务器的地址。但是需要注意我们要把文件上传到cdn服务器才行,并且只对html影响。
},
复制代码
mode
Mode⽤来指定当前的构建环境
- production
- development
- none
设置mode可以⾃动触发webpack内置的函数,达到优化的效果。
开发阶段的开启会有利于热更新的处理,识别哪个模块变化。
⽣产阶段的开启会有帮助模块压缩,处理副作⽤等⼀些功能。
loader
模块解析,模块转换器,⽤于把模块原内容按照需求转换成新内容。
由于 webpack 自身只能打包 JS 、JSON代码,也就意味着,当我们的项目里面,使用了 css、less、sass、jsx 等浏览器不能识别的代码时,webpack 默认是不能对这些代码进行处理。所以这个时候,我们就需要在 webpack 中引入一些其他的工具。而这些工具,我们就称之为 “loaders”。注意loader顺序:从右到左(或从下到上)地取值或执行
常⻅的loader:
style-loader
css-loader
less-loader
sass-loader
ts-loader //将Ts转换成js
babel-loader//转换ES6、7等js新特性语法
file-loader//处理图⽚
eslint-loader // eslint
...
复制代码
loaders 的配置
所有 loaders 的配置,都是在 module.rules
的数组中进行配置:
module: {
rules: [
]
}
复制代码
css 打包配置
当我们只是下载安装了css-loader时,引入是没效果的,因为实质上是css in js 的方式,把css代码,以字符串的形式提取放到bundle文件里,所以浏览器并没有解析到css。所以还需要一个style-loader,用于把css字符串从bundle中提取出来,在html中的头部创建一个style标签,把css字符串放style里面,从而浏览器能够读取解析到css。
下载 loaders
npm i style-loader css-loader -D
复制代码
配置 loaders
module: {
rules: [
// 打包 css
{
// test 用于配置当前打包规则要匹配的文件名
test: /\.css$/i,
// use 用于配置当前打包规则所使用的 loader
// 当处理一个模块需要多个loader的时候,需要是一个数组
// 执行顺序: 自后往前
// loader官方推荐,一个loader只做一件事情
// style-loader是通过js动态生成css直接打包进js⾥的,如果要单独生成css文件,需要借助plugin
use: ['style-loader', 'css-loader']
//use: {
// loader: 'css-loader'
//}
}
]
}
复制代码
less 打包配置
下载 loaders
npm i less less-loader -D
复制代码
配置 loaders
{
test: /\.less$/i,
use: ['style-loader', 'css-loader', 'less-loader'],
exclude: /node_modules/,
}
复制代码
注意: 如果出现了this.getOptions is not a function
报错信息,是因为less-loader版本过高,不能兼容,需要降低版本。
npm uninstall less-loader
npm install less-loader@5.0.0
复制代码
scss 打包配置
下载loaders
npm i node-sass sass-loader -D
npm i node-sass -D --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/
复制代码
配置loaders
{
test: /\.scss/i,
use: ['style-loader', 'css-loader', 'sass-loader'],
exclude: /node_modules/,
}
复制代码
plugins 插件
插件: 是一种作用于webpack整个打包生命周期的机制。
每一个插件都会对准一个生命周期,比如打包前、生成资源文件前、生成资源文件后等。
plugin 可以在webpack运⾏到某个阶段的时候,帮你做⼀些事情,类似于⽣命周期的概念
扩展插件,在 Webpack 构建流程中的特定时机注⼊扩展逻辑来改变构建结果或做你想要的事情。作⽤于整个构建过程。
plugins 插件基本配置
module.exports = {
// 插件配置
plugins: [
]
}
复制代码
html-webpack-plugin
htmlwebpackplugin会在打包结束后,⾃动⽣成⼀个html⽂件,并把打包⽣成的js模块引⼊到该html中。
下载
npm i html-webpack-plugin -D
复制代码
引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
复制代码
配置使用
module.exports = {
// 插件配置
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // 模板
filename: 'index.html', // 生成的html名字
chunks: ['index'] // 加载哪些js
})
]
}
复制代码
配置说明:
title: ⽤来⽣成⻚⾯的 title 元素
filename: 输出的 HTML ⽂件名,默认是 index.html, 也可以直接配置带有⼦⽬录。
template: 模板⽂件路径,⽀持加载器,⽐如 html!./index.html
inject: true | 'head' | 'body' | false ,注⼊所有的资源到特定的 template 或者templateContent 中,如果设置为 true 或者 body,所有的 javascript 资源将被放置到 body元素的底部,'head' 将放置到 head 元素中。
favicon: 添加特定的 favicon 路径到输出的 HTML ⽂件中。
minify: {} | false , 传递 html-minifier 选项给 minify 输出
hash: true | false, 如果为 true, 将添加⼀个唯⼀的 webpack 编译 hash 到所有包含的脚本和CSS ⽂件,对于解除 cache 很有⽤。
cache: true | false,如果为 true, 这是默认值,仅仅在⽂件修改之后才会发布⽂件。
showErrors: true | false, 如果为 true, 这是默认值,错误信息会写⼊到 HTML ⻚⾯中
chunks: 允许只添加某些块 (⽐如,仅仅 unit test 块)
chunksSortMode: 允许控制块在添加到⻚⾯之前的排序⽅式,⽀持的值:'none' | 'default' |{function}-default:'auto'
excludeChunks: 允许跳过某些块,(⽐如,跳过单元测试的块)
复制代码
clean-webpack-plugin
清除打包中的多余文件。
下载
npm i clean-webpack-plugin -D
复制代码
引入
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
复制代码
配置使用
module.exports = {
// 插件配置
plugins: [
new CleanWebpackPlugin()
]
}
复制代码
mini-css-extract-plugin
之前我们说到了,style-loader是通过js动态生成css直接打包进js⾥的,但是我们希望能单独生成css文件,因为这样就可以和js并行下载提高页面加载效率,缺点就是会增加请求。
下载
npm i mini-css-extract-plugin -D
复制代码
引入
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
复制代码
配置使用
module.exports = {
module: {
rules: [
// 打包 css
{
// test 用于配置当前打包规则要匹配的文件名
test: /\.less$/,
// use 用于配置当前打包规则所使用的 loader
// 使用MiniCssExtractPlugin.loader来替代style-loader
// 但是需要注意的是,抽离了css成文件夹之后,引用层级问题,需要使用../
// use: [ MiniCssExtractPlugin.loader, 'css-loader', "postcss-loader", 'less-loader'],
use: [ {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}, 'css-loader', "postcss-loader", 'less-loader'],
// include用于引入符合以下任何条件的模块
include: path.resolve(__dirname, './src')
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name]_[contenthash:4].css",
chunkFilename: "[id].css"
})
]
}
复制代码
moudle
在node中⼀切皆模块,Webpack 是基于node的,⼀个模块对应着⼀个⽂件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
当webpack处理到不认识的模块时,需要在webpack中的module处进⾏配置,当检测到是什么格式的模块,使⽤什么loader来处理。
module:{
rules:[
{
test:/\.xxx$/,//指定匹配规则
use:{
loader: 'xxx-load'//指定使⽤的loader
}
}
]
}
复制代码
file-loader
file-loader,处理静态资源模块。 原理是把打包⼊⼝中识别出的资源模块,移动到输出⽬录,并且返回⼀个地址名称。
所以我们什么时候⽤file-loader呢?
场景:就是当我们需要模块,仅仅是从源代码挪移到打包⽬录,就可以使⽤file-loader来处理,txt,svg,csv,excel,图⽚资源等等
安装: npm install file-loader -D
复制代码
使用:
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
//use使⽤⼀个loader可以⽤对象,字符串,两个loader需要⽤数组
use: {
loader: "file-loader",
// options额外的配置,⽐如资源名称
options: {
// placeholder 占位符 [name]⽼资源模块的名称
// [ext]⽼资源模块的后缀
// https://webpack.js.org/loaders/file-loader#placeholders
name: "[name]_[hash].[ext]",
//打包后的存放位置
outputPath: "images/"
}
}
}
]
}
复制代码
样式处理:
css-loader 分析css模块之间的关系,并合成⼀个css
loader执⾏顺序:从后往前
Style-loader 会把css-loader⽣成的内容,以style挂载到⻚⾯的heade部分
npm install style-loader css-loader -D
复制代码
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
{
test: /\.css$/,
use: [{
loader: "style-loader",
options: {
injectType: "singletonStyleTag" // 将所有的style标签合并成⼀个
}
}, "css-loader"]
}
复制代码
生产、开发模式区分打包
借助插件webpack-merge
安装:
npm install webpack-merge -D
复制代码
将配置拆分为基本配置、开发配置、生产配置,然后通过webpack-merge
来合并配置。
使用:
const { merge } = require('webpack-merge'); // 最新版本的 需要这样来拿取merge函数
const commonConfig = require('./webpack.common.js');
const proConfig = {
mode: 'production',
module: {
// xxxxx
},
plugins: {
// xxxxx
}
}
module.exports = merge(commonConfig, proConfig);
复制代码
修改package.json文件:
"dev": "webpack-dev-server --config ./build/webpack.dev.js",
"build": "webpack --config ./build/webpack.pro.js",
"start": "npm run dev"
复制代码
注意:在开发环境中,图片使用chunkhash会报错,推荐使用hash。
cross-env
安装:
npm i cross-env -D
复制代码
修改package.json文件:
"dev": "cross-env NODE_ENV=development webpack-dev-server --config ./build/webpack.dev.js",
"build": "cross-env NODE_ENV=production webpack --config ./build/webpack.pro.js",
"start": "npm run dev"
复制代码
获取:
在各个配置文件中,都可以通过process.env.NODE_ENV
拿取到参数。
其他插件
WebpackDevServer
WebpackDevServer可以帮我们自动打包和刷新页面,可以提升开发效率。
安装:
npm i webpack-dev-server -D
复制代码
修改package.json
"scripts": {
// xxx
"server": "webpack-dev-server"
},
复制代码
在webpack.config.js配置:
devServer: {
contentBase: path.resolve(__dirname, '../dist'), // 默认会以根文件夹提供本地服务器,这里指定文件夹(指向静态资源目录)
inline: true, // 自动刷新
hot: true, // 开启热模块替换
historyApiFallback: true, // 在开发单页应用时非常有用,它依赖于HTML5 history API,如果设置为true,所有的跳转将指向index.html
open: true, // 服务启动之后,会自动帮我们打开浏览器窗口
publicPath: '/',
compress: true, // 使用gzip压缩
stats: 'minimal',
port: 8080 // 端口号,默认是8080
},
复制代码
启动:
npm run server
复制代码
启动过程中,可能会出现以下报错:
Cannot find module 'webpack-cli/bin/config-yargs'
复制代码
该报错的原因是由于 webpack-cli@^4.3.0
的版本与 webpack-dev-server@^3.11.0
版本冲突,需要将 webpack-cli
的版本降低为 3.x 的版本:
npm uninstall webpack-cli
npm i webpack-cli@3 -D
复制代码
低版本下载完成后,重新执行启动命令 npm run server
启动服务器。
启动服务成功后,会发现dist中文件没有了,这是因为devServer把打包后的模块不会放在dist⽬录下,⽽是放到内存中,从⽽提升速度。
devtool
源代码与打包后的代码的映射关系,通过配置可以定位到具体的源代码。例如代码中出现错误,那么我们就可以定位到具体的地方来查看
- source-map: 产⽣ .map ⽂件
- cheap: 只包含行信息,不包含列信息。也就是说是定位到具体的某一行,但不显示是哪一列。
- Module:包含loader的sourcemap(第三⽅模块)
- eval: 使⽤eval包裹模块代码(速度最快)
配置中添加:
devtool: 'cheap-source-map',
复制代码
然后重新执行启动命令 npm run dev
启动服务器。
在开发环境中,官方建议配置为cheap-eval-module-source-map
。