本篇博客仅适用未了解过或者没入门过 webpack 的小伙伴作为入门级的了解。
介绍
webpack是一个现代的JavaScript应用的静态模块打包工具。
随着 SPA 单页应用的发展,使用的 js/css/png 等静态资源较多且难以管理,文件夹结构也容易混乱。很多时候我们希望项目可以具备压缩css,js 正确地处理各种 js/css 的 import 以及相关的模板 html 文件。 webpack 的出现就解决了这个难题。
在官网首页就有这样一张图,bundle your assets
本质上,webpack 是一个用于现代 JavaScript 应用程序的_静态模块打包工具_。当 webpack 处理应用程序时,它会在内部构建一个 依赖图(dependency graph),此依赖图对应映射到项目所需的每个模块,并生成一个或多个 bundle。
安装
全局安装
代码语言:javascript复制npm install webpack -g
安装完可以用命令行 webpack -h
查看。
单独安装
通常我们会将 Webpack 安装到项目的依赖中,这样就可以使用项目本地版本的 Webpack。
代码语言:javascript复制# 进入项目目录
# 确定已经有 package.json,没有就通过 npm init 创建
npm init
# 安装 webpack 依赖
npm install webpack --save-dev
核心概念
在开始前你需要先理解一些__核心概念__:
- 入口(entry)
- 输出(output)
- loader
- 插件(plugin)
- 模式(mode)
- 浏览器兼容性(browser compatibility)
- 环境(environment)
一个非常重要的知识:
webpack 开箱即用,可以无需使用任何配置文件。然而,webpack 会假定项目的入口起点为 src/index.js
,然后会在 dist/main.js
输出结果,并且在生产环境开启压缩和优化。通常你的项目还需要继续扩展此能力,为此你可以在项目根目录下创建一个 webpack.config.js
文件,然后 webpack 会自动使用它。
还有一个快速生成符合项目要求的 webpack 配置文件的方法,在使用 webpack-cli 的 init
命令时,会在创建配置文件之前会询问你几个问题。
npx webpack-cli init
入口(entry)
__入口起点(entry point)__指示 webpack 应该使用哪个模块,来作为构建其内部 依赖图(dependency graph) 的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。 默认值是
./src/index.js
,但你可以通过在 webpack configuration 中配置entry
属性,来指定一个(或多个)不同的入口起点。
基本的单入口写法
webpack.config.js
代码语言:javascript复制module.exports = {
entry: './path/to/my/entry/file.js'
};
多入口甚至分离式写法,参考官方文档。
输出(output)
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件。主要输出文件的默认值是
./dist/main.js
,其他生成文件默认放置在./dist
文件夹中。 你可以通过在配置中指定一个output
字段,来配置这些处理过程。
webpack.config.js
代码语言:javascript复制const path = require("path")
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, "dist")
}
}
module.exports = config
loader
loader 用于对模块的源代码进行转换。loader 可以使你在
import
或 "load(加载)" 模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的得力方式。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript 或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中import
CSS文件
例如,你可以使用 loader 告诉 webpack 加载 CSS 文件,首先安装相对应的 loader:
代码语言:javascript复制npm install --save-dev css-loader
然后指示 webpack 对每个 .css
使用 css-loader
webpack.config.js
代码语言:javascript复制module.exports = {
module: {
rules: [
{
test: /.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
应保证 loader 的先后顺序:'style-loader'
在前,而 'css-loader'
在后。如果不遵守此约定,webpack 可能会抛出错误。
loader
从右到左(或从下到上)倒序执行,test
// 正则匹配打包过程中的文件路径,use
// 所用到的加载器-倒序执行
webpack 根据正则表达式,来确定应该查找哪些文件,并将其提供给指定的 loader。在这个示例中,所有以 .css
结尾的文件,都将被提供给 style-loader
和 css-loader
。
完整示例
代码语言:javascript复制│ package-lock.json
│ package.json
│ webpack.config.js
│
├─ src
│ index.css
| index.js
index.css
代码语言:javascript复制body {
background: #b86060;
}
index.js
代码语言:javascript复制import './index.css'
console.log("Hello Webpack")
安装对应的loader
代码语言:javascript复制npm install --save-dev style-loader css-loader
webpack.config.js
代码语言:javascript复制const path = require("path")
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, "dist")
},
module: {
rules: [
{
test: /.css$/i,
use: ['style-loader', 'css-loader']
}
]
}
}
module.exports = config
执行打包
代码语言:javascript复制npm run build
在 dist
文件夹下新建一个 index.html
,引入编译后的 js
文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="./bundle.js"></script>
</body>
</html>
在浏览器中打开该文件,可以看到之前写好的 css
背景颜色就生效了。
关于loader的官方文档
关于管理资源篇的官方文档
plugin
__插件__是 webpack 的 支柱 功能。webpack 自身也是构建于你在 webpack 配置中用到的__相同的插件系统__之上!插件目的在于解决 loader 无法实现的__其他事__。由于__插件__可以携带参数/选项,你必须在 webpack 配置中,向
plugins
属性传入一个new
实例。
用法
由于__插件__可以携带参数/选项,你必须在 webpack 配置中,向 plugins
属性传入一个 new
实例。
示例:使用html-webpack-plugin生成html模板
代码语言:javascript复制npm install --save-dev html-webpack-plugin
webpack.config.js
HtmlWebpackPlugin
将生成一个 HTML 文件,并在其中使用 script
引入一个名为 my-first-webpack.bundle.js
的 JS 文件。
const path = require("path")
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.join(__dirname, "dist")
},
module: {
rules: [
{
test: /.css$/i,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: "hello.html", // 模板html
filename: "index.html" // 生成的html文件名
})
]
}
module.exports = config
根目录/hello.html
代码语言:javascript复制<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>Hello 乐心湖</h1>
</body>
</html>
运行编译 npm run build
在 ./dist
可以看到 HtmlWebpackPlugin
就将我们的模板给整成 index.html
,并且引入了 entry-js
模式(mode)
通过选择
development
,production
或none
之中的一个,来设置mode
参数,你可以启用 webpack 内置在相应环境下的优化。其默认值为production
。
只需在配置对象中提供 mode
选项:
module.exports = {
mode: 'development'
};
支持以下字符串值:
选项 | 描述 |
---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
none | 不使用任何默认优化选项 |
如果没有设置,webpack 会给 mode
的默认值设置为 production
。
也就是说你可以在 js
中使用
if(process.env.NODE_ENV === 'development'){
}
热更新
模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块, 而无需完全刷新。本页面重点介绍其 实现。
HMR 不适用于生产环境,这意味着它应当用于开发环境。
启用 HMR
安装
代码语言:javascript复制npm install webpack-dev-server --save-dev
webpack.config.js
代码语言:javascript复制devServer: {
contentBase: './dist', // 热更新的目录
hot: true, // 开启
},
package.json
代码语言:javascript复制"scripts": {
"hot": "webpack serve"
},
执行 npm run hot
在打印的日志中可以看到一个链接,默认是8080端口。
之后你修改 css
html
js
都会自动编译,不过有时候可能需要你手动刷新浏览器才看得到效果。
关于 Webpack 其他厉害的技巧和知识建议查看官方文档,本笔记大篇幅也是复制参考官方指南而写。