Fork me on GitHub

适合新手看的webpack安装和使用教程

现在前端开发越来越偏向模块化,我们的项目也逐渐转向脚手架搭建。这其中,webpack的力量是巨大的,之前因为不了解webpack的某些配置所以在项目中也耽搁了一些时间,因此我觉得很有必要深入了解下webpack。之后需要自己尝试手动搭建项目工程,才能真正理解脚手架的原理。

webpack

官方的话来说,Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。

接下来让我们安装并初步配置下webpack4吧~

全局安装

全局安装,安装成功之后可以在全局使用webpack

1
2
npm install -g webpack
npm install -g webpack-cli

全局安装失败可能是网络的原因,可以使用淘宝镜像安装:

1
cnpm install webpack -g

栗子初体验

初始化

新建一个文件夹weproject并初始化项目:

1
2
cd weproject
npm init

npm init会自动创建一个package.json文件,这个文件存放着当前项目的相关信息。

安装webpack

在项目中安装webpack:

1
npm install --save-dev webpack webpack-cli

构建目录

新建文件夹src

1
mkdir src

在src文件夹中新建一个index.js。该文件是webpack的入口文件。webpack打包后会自动生成一个dist文件夹,默认生成构建文件main.js

1
2
//index.js
document.write("I'm index.js")

在src文件夹中新建一个新建静态页面index.html,方便之后查看效果:

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index</title>
</head>
<body>
<script src="../dist/main.js"></script>
</body>
</html>

webpack4是可以不用手动配置(webpack会提供一套默认配置),但如果需要自定义配置,我们可以新建一个webpack的配置文件webpack.config.js,通过配置文件可以告诉webpack需要做些什么。

如下,在该文件中配置了入口文件和输出文件的路径:

1
2
3
4
5
6
7
8
9
let path = require('path')

module.exports = {
entry: './src/index.js', //入口文件
output: { //打包出口文件
path: path.resolve(__dirname, 'dist'),
filename: './main.js'
}
};

PS: 可以通过npx直接执行node_modules中的依赖。

执行webpack

在文件夹中执行命令webpack可以看到打包后的js文件在自动生成的dist文件夹中:

1
webpack //或者 webpack --mode development

在浏览器打开index.html可以查看效果,说明webpack把src/index.js文件打包成dist/main.js了。

修改执行命令

只需在package.json的scripts中加入:

1
2
3
4
5
"scripts": {
// ...
"dev":"webpack",
"build":"webpack --mode production"
}

就可以用npm run dev代替webpack,用npm run build代替webpack --mode production了。

新建模块

新建一个module.js:

1
2
//module.js
module.exports = "I'm module.js"

在index.js中引用module.js:

1
2
3
// ...
let myModule = require('./module.js')
alert(myModule)

重新执行npm run dev打开页面可以看到页面变化。webpack会分析入口文件,并解析包含依赖关系的文件,把他们都打包到main.js中。

让配置文件支持智能提示

通过 Configuration 让 VSCode 提供webpack配置的智能提示,修改webpack.config.js为:

1
2
3
4
5
6
7
8
9
10
11
// 运行webpack时注释下面这句
import { Configuration } from 'webpack'

/**
* @type {Configuration}
*/
const config = {
//...配置项
}

module.exports = config

到这里我们就初步了解了webpack的安装和使用啦,不过如果要实现更多自定义功能的话,我们还需要了解webpack的几个核心概念。

webpack核心概念

webpack的核心有以下几点:

  1. Entry:入口
  2. Output:出口
  3. Loader:加载器
  4. Plugins:插件
  5. Mode:模式

Entry

入口文件,默认是src/index.js,entry可以是字符串(单入口),可以是数组或对象(多入口),如下:

1
2
3
module.exports = {
entry: './src/index.js',
}

1
2
3
4
5
6
7
8
module.exports = {
entry: {
main: [
'./src/index.js',
'./src/index2.js'
]
}
}

webpack会解析多个入口文件的依赖后进行打包。

Output

输出文件,是一个对象,webpack默认创建的输出内容就是 ./dist/main.js。也可以自定义路径:

1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js运行在nodeJs环境中,可以使用nodeJS的内置模块
const path = require('path')

module.exports = {
output: {
// filename: 'main.js',
// 或(生成hash结尾)
filename: '[name].[contenthash].js'
path: path.resolve(__dirname, 'dist')
}
}

path

表示生成文件的根目录,需要传入一个绝对路径。path参数和后面的filename参数共同组成入口文件的完整路径。

publicPath

表示一个URL路径(指向生成文件的根目录),用于生成css/js/图片/字体文件等资源的路径。 publicPath参数跟path参数的区别是:path参数其实是针对本地文件系统的,而publicPath则针对的是浏览器,因此,publicPath既可以是一个相对路径,也可以是一个绝对路径。

filename

表示如何命名生成出来的入口文件

chunkFilename

chunkFilename参数与filename参数类似,都是用来定义生成文件的命名方式的,只不过,chunkFilename参数指定的是除入口文件外的chunk(这些chunk通常是由于webpack对代码的优化所形成的,比如因应实际运行的情况来异步加载)的命名。

Loader

Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件(如css,图片,字体等),就需要使用 loader 进行转换。可以理解为Loader 将各个类型的文件,转换为JS代码能够为webpack所打包。

Loader 可以在require()引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

打包css(css-loader)

新建一个文件style.css:

1
body { background: #fc9; }

加载css需要安装以下loader:

1
npm install css-loader style-loader  --save-dev

过程:css-loader将css模块转成js交给webpack打包,style-loader将css打包结果通过style标签添加到页面上。

修改webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
// ...
module.exports = {
// ...
module:{
rules: [
{
test: /\.css$/,
use: ["style-loader","css-loader"]
// 多个loader的执行顺序是从后往前执行,css-loader应该放后面
}
]
}
}

在index.js中引用css文件(webpack建议在js文件中引入css等资源文件,更方便建立依赖关系):

1
2
3
// ...
// require('./style.css')
import './style.css'

重新执行打包,打开页面就可以看到背景颜色了。

处理图片

我们添加图片在项目中后(我的图片统一放在项目的img文件夹下),可以在style.css中继续补充:

1
2
3
4
5
6
.box {
width: 200px;
height: 200px;
background: url('../img/bg.jpg') no-repeat;
background-size: 100% 100%;
}

在index.html中添加一个div:

1
<div class="box"></div>

加载图片需要安装以下loader:

1
npm install url-loader  --save-dev

修改webpack.config.js,在module.rules中加入配置:

1
2
3
4
5
6
//...
{
test: /\.(jpg|png|gif|jpeg)$/,
loader: 'url-loader'
}
//...

重新执行打包就可以看到效果了。

  • file-loader:能够根据配置项复制使用到的资源到构建之后的文件夹,并且能够更改对应的链接。
  • url-loader :包含 file-loader 的全部功能,并且能够根据配置将符合配置的文件转换成 Base64 方式引入,将小体积的图片 Base64 引入项目可以减少 http 请求。

压缩图片

安装image-webpack-loader:

1
npm install image-webpack-loader --save-dev

修改配置项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ...
{
test: /\.(png|jpg|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[ext]'
}
},
{
loader:'image-webpack-loader',
options: {
bypassOnDebug: true,
}
}
]
}

处理字体等(file-loader)

处理字体和图片差不多,首先我把下载的字体文件放在新建的icon文件夹,如下:

1
npm install file-loader  --save-dev

修改webpack.config.js,在module.rules中加入配置:

1
2
3
4
5
6
7
8
9
10
//...
{
// exclude排除资源
exclude: /\.(css|js|html|less|json|jpg|png|gif)$/,
loader: 'file-loader',
options: {
name:'[hash:10].[ext]'
},
}
//...

在入口文件引入iconfont.css, 并index.html中使用iconfont:

1
<i class="iconfont icon-jia"></i>

重新执行打包就可以看到效果了。

编译JS文件(babel-loader)

安装babel相关依赖:

1
npm install babel-loader @babel/core @babel/preset-env --save-dev

配置loader匹配JS文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// ...
module:{
rules: [
// ...
{
test: /\.js$/,
exclude: /node_modules/,
user: {
loader: 'babel-loader',
// loader的配置
options: {
// js转译成es5
presets: ['@babel/preset-env']
}
}
}
]
}

Plugins

插件目的在于解决 loader无法实现的其他事,增强webpack在项目自动化构建方面的能力。插件接口功能极其强大,可以用来处理各种各样的任务。

想要使用一个插件,你只需要require()它,然后把它添加到 plugins 数组中。

自动构建html(html-webpack-plugin)

webpack支持自动创建html文件,首先得安装插件html-webpack-plugin

1
npm install html-webpack-plugin --save-dev

然后在配置文件webpack.config.js中引用并调用该插件:

1
2
3
4
5
6
7
8
// ...
let HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// ...
plugins:[
new HtmlWebpackPlugin()
]
}

执行命令webpack会自动创建相应的html和js文件,并自动引用相应的静态资源文件。

如果需要自定义html路径或者增加其他配置,可以修改HtmlWebpackPlugin的参数:

1
2
3
4
5
6
new HtmlWebpackPlugin({
title: '首页',
meta: {
viewport: 'width=device-width'
}
})

自动生成html的优势:

  • html输出在dist中,方便打包发布
  • html中的script是自动引入的,确保资源文件路径正常

如果需要对html进行大量自定义,最好在源代码中添加生成html模板。如在src修改index.html作为模板:

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%=htmlWebpackPlugin.options.title%></title>
</head>
<body>
<h1>标签1</h1>
<div id="app"></div>
</body>
</html>

修改插件配置:

1
2
3
4
new HtmlWebpackPlugin({
template: './src/index.html',
title: '首页',
})

如果在plugin中添加多个HtmlWebpackPlugin实例,可以打包出多个html。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ...
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
title: '首页',
filename: 'index.html',
chunks: ['index'] //指定使用的js, 在entry中可以用对象指定多个入口文件
}),
new HtmlWebpackPlugin({
template: './src/about.html',
title: '关于',
filename: 'about.html',
chunks: ['about'] //指定使用的js, 在entry中可以用对象指定多个入口文件
})
]

压缩JS(terser-webpack-plugin)

压缩打包的js文件,可以减少文件体积。安装插件:

1
npm i terser-webpack-plugin --D

引入插件配置:

1
2
3
4
5
6
7
8
9
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
// ...
optimization: {
minimize: true, //是否压缩
minimizer: [new TerserPlugin()], //压缩工具
},
}

清理dist文件夹(clean-webpack-plugin)

每次打包之后都会生成dist文件夹,而生成的文件夹不会清理掉之前遗留的文件,会造成不必要的资源浪费。因此我们打包之前最好删除之前的dist文件夹,或者配置自动清除dist文件夹的插件clean-webpack-plugin

1
npm i -D clean-webpack-plugin

然后在配置文件webpack.config.js中引用并调用该插件:

1
2
3
4
5
6
7
8
9
10
// ...
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
// ...
plugins:[
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ["dist"],
}),
]
}

这样我们下次打包的时候就会自动清理上次打包的文件啦~

复制文件(copy-webpack-plugin)

建议处理无需打包的静态文件(如图标等),一般把静态文件放在public或者static文件夹中,然后把该文件夹下所有文件直接复制到dist中,安装:

1
npm i -D copy-webpack-plugin

引用插件:

1
2
3
4
5
6
7
8
9
10
// ...
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
// ...
plugins:[
new CopyPlugin([
'public' //需要copy的文件路径
]),
]
}

分析文件大小(webpack-bundle-analyzer)

安装一个可视化的打包分析工具:

1
npm i webpack-bundle-analyzer --D

在配置文件中修改:

1
2
3
4
5
6
7
8
const BundlePlugin = require('webpack-bundle-analyzer')

module.exports = {
// ...
plugins:[
new BundlePlugin.BundleAnalyzerPlugin({),
]
}

启动就可以看到文件大小分布图。

Mode

webpack的工作模式:

  • production(默认):启动内置优化插件,自动优化打包结果,打包速度偏慢
  • development: 自动优化打包速度,添加一些调试过程中的辅助插件
  • none: 不会做优化操作,一般用于分析模块打包结果

其他优化

自动编译刷新(webpack-dev-server)

每次修改代码后,都需要执行打包命令重新打包才能看到新的页面效果,webpack提供一个代理服务器可以监听文件编号并自动重新编译:

1
npm i webpack-dev-server --D

在package.json中指定启动服务并自动打开浏览器的命令:

1
2
3
4
//...
"scripts": {
"start": "webpack serve --open"
}

修改配置指定server从哪里修改代码:

1
2
3
4
5
6
7
8
module.exports = {
// ...
devServer: {
static: './dist',
port: 9000,
contentBase: 'public'// 静态资源目录需要额外加配置
}
}

如果需要启动热更新(HMR),即不刷新页面只更新部分模块,可以在配置文件的devServer中增加:

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
// ...
devServer: {
// 开启HMR
hot: true
},
// ...
plugins: [
// ...
new webpack.HotModuleReplacementPlugin()
]
}
-------------完结撒花 -------------

本文标题:适合新手看的webpack安装和使用教程

文章作者:咕噜咕噜

发布时间:2020年03月12日

最后更新:2022年09月11日

原始链接:https://aartemida.github.io/2020/03/12/webpack安装使用/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。