专栏名称: 前端外刊评论
最新、最前沿的前端资讯,最有深入、最干前端相关的技术译文。
目录
相关文章推荐
前端早读课  ·  【第3453期】圈复杂度在转转前端质量体系中的应用 ·  19 小时前  
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
前端早读课  ·  【第3451期】前端 TypeError ... ·  2 天前  
51好读  ›  专栏  ›  前端外刊评论

前端负责人教你使用 Webpack

前端外刊评论  · 公众号  · 前端  · 2019-07-18 09:02

正文

1 Webpack 有什么特点?

图片来源于网络

Webpack 是一款强大的打包工具。在 Webpack 中一切皆模块。Webpack 官网的 banner 图完美地诠释了这一理念。Webpack 从一个入口文件开始递归地分析模块的依赖关系,根据依赖关系将这些模块打包成一个或多个文件。

目前几乎所有的前端构建和开发都是采用 Webpack 。因为 Webpack 有强大的社区生态,每月 Webpack 的下载量超过百万。通过 loader、plugin 支持 Webpack 与主流的前端框架和语言进行集成,比如 Vue、React、TypeScript。

那么,Webpack 有什么特点?

  • 支持所有的模块化 可以对 ES6 模块、CommonJS 模块、AMD 模块等所有标准的模块进行打包。

  • code splitting 可以将代码打成多个 chunk,按需加载,意味着我们的站点无需等待整个 js 资源下载完成之后才能交互,可以大大提升速度。

  • 强大灵活的插件系统 Webpack 提供了很多内置的插件,包括其自身也是架构在插件系统上可以满足所有的打包需求。

  • loader 借助 loader 预处理非 js 资源,Webpack 可以打包所有的静态资源。

2 Webpack 如何构建?

Webpack 的构建流程是一种事件流机制。整个构建流程可以看成是一个流水线,每个环节负责单一的任务,处理完将进入下一个环节。Webpack 会在每个环节上发布事件,供内置的和自定义的插件有机会干预 Webpack 的构建过程,控制 Webpack 的构建结果。Webpack 的基本的构建流程图如下:

  • 初始化 读取 webpack 配置文件和 shell 脚本中的参数,将参数合并后初始化 Webpack ,生成 Compiler 对象。

  • 开始编译 执行 Compiler 的 run 方法开始执行编译。

  • 编译完成 从入口文件开始,调用配置中的 loader 对模块进行编译,并梳理出模块间的依赖关系,直至所有的模块编译完成。

  • 资源输出 根据入口与模块间的依赖关系,将上一步编译完成的内容组装成一个个的 chunk (代码块),然后把 chunk 加入到等待输出的资源列表中。

  • 完成 确定好输出资源后,根据指定的输出路径和文件名配置,将资源写入到磁盘的文件系统中,完成整个构建过程。

3 你需要知道哪些核心概念?

1. 入口

入口是 Webpack 进行构建的起点,Webpack 在构建过程中从入口文件开始,递归地编译模块,并分析模块间的依赖关系,最终得出依赖图。Webpack 依据该依赖图对模块进行组装,输出到最终的 bundle 文件中。

我们可以在 Webpack 的配置文件中配置 entry 属性,来指定入口文件,入口文件可以是一个也可以指定多个。

我们来看一个例子:

  1. // webpack.config.js

  2. module.exports = {

  3. entry: './src/app.js'

  4. };

配置多个入口的场景常见于多页应用中。如果配置多个入口可以这样:

  1. // webpack.config.js

  2. module.exports = {

  3. entry: {

  4. pageOne: './src/pageOne/app.js',

  5. pageTwo: './src/pageTwo/app.js'

  6. }

  7. };

2. 输出

配置 output 选项可以指示 Webpack 如何去输出、在哪里输出我们的静态资源文件。

我们通过一个例子来看一下 output 如何使用:

  1. // webpack.config.js

  2. module.exports = {

  3. output: {

  4. filename: 'bundle.js',

  5. path: './dist'

  6. }

  7. };

上例中,我们指示 Webpack 最终的输出文件名为 bundle . js ,输出的目录为 ./ dist

3. loader

loader 的使用

Webpack 本身是不能处理非 JS 资源的,但我们却可以在 Webpack 中引入 css、图片、字体等非 js 文件。例如:

  1. // app.js

  2. import Styles from './styles.css';

那么 Webpack 是如何实现的呢?

Webpack 中使用 loader 对非 js 文件进行转换。loader 可以在我们 import 或者加载模块时,对文件进行预处理,将非 js 的文件内容,最终转换成 js 代码。

loader 有三种使用方式:

  • 配置 在 webpack.config.js 文件中指定

  • 内联 在每个 import 语句中线上指定

  • CLI 在 shell 命令中指定。

在实际的应用中,绝大数都是采用配置的方式来使用,一方面在配置文件中,可以非常直观地看到某种类型的文件使用了什么 loader,另一方面,在项目复杂的情况下,便于进行维护。

我们通过一个简单的例子来看一下 loader 的使用:

  1. // webpack.config.js

  2. module.exports = {

  3. module: {

  4. rules: [

  5. { test: /\.css$/, use: 'css-loader' }

  6. ]

  7. }

  8. };

我们需要告诉 Webpack 当遇到 css 文件的时候,使用 css - loader 进行预处理。这里由于 css-loader 是单独的 npm 模块,使用前我们需要先进行安装:

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

常用的 loader

Webpack 可以处理任何非 JS 语言,得益于社区提供的丰富的 loader,日常开发中所使用到的 loader,都可以在社区找到。这里对一些常用的 loader 进行简要的说明。

  • babel-loader 将 ES2015+ 代码转译为 ES5。

  • ts-loader 将 TypeScript 代码转译为 ES5。

  • css-loader 解析 @import url () ,并对引用的依赖进行解析。

  • style-loader 在 HTML 中注入 标签将 css 添加到 DOM 中。通常与 css - loader 结合使用。

  • sass-loader 加载 sass/scss 文件并编译成 css。

  • postcss-loader 使用 PostCSS 加载和转译 css 文件。

  • html-loader 将 HTML 导出为字符串。

  • vue-loader 加载和转译 Vue 组件。

  • url-loader file - loader 一样,但如果文件小于配置的限制值,可以返回 data URL

  • file-loader 将文件提取到输出目录,并返回相对路径。

4. plugin

插件的使用

插件是 Webpack 的非常重要的功能,Webpack 本身也是建立在插件系统之上的。插件机制极大增强了 Webpack 的功能,为 Webpack 增加了足够的灵活性。通过插件,我们可以在 Webpack 的构建过程中,引入自己的操作,干预构建结果。

我们通过一个示例来看一下插件的使用:

  1. // webpack.config.js

  2. const HtmlWebpackPlugin = require('html-webpack -plugin');

  3. const webpack = require('webpack');


  4. const config = {

  5. plugins: [

  6. new webpack.optimize.UglifyJsPlugin(),

  7. new HtmlWebpackPlugin({template: './src/index.html'})

  8. ]

  9. };


  10. module.exports = config;

示例中,我们用到了两个插件,一个是内置的 UglifyJsPlugin 插件,该插件对 js 进行压缩,减小文件的体积。一个是外部插件 HtmlWebpackPlugin ,用来自动生成入口文件,并将最新的资源注入到 HTML 中。

常用的插件

  • HtmlWebpackPlugin 自动生成入口文件,并将最新的资源注入到 HTML 中。

  • CommonsChunkPlugin 用以创建独立文件,常用来提取多个模块中的公共模块。

  • DefinePlugin 用以定义在编译时使用的全局常量。

  • DllPlugin 拆分 bundle 减少不必要的构建。

  • ExtractTextWebpackPlugin 将文本从 bundle 中提取到单独的文件中。常见的场景是从 bundle 中将 CSS 提取到独立的 css 文件中。

  • HotModuleReplacementPlugin 在运行过程中替换、添加或删除模块,而无需重新加载整个页面。

  • UglifyjsWebpackPlugin 对 js 进行压缩,减小文件的体积。

  • CopyWebpackPlugin 将单个文件或整个目录复制到构建目录。一个常用的场景是将项目中的静态图片不经构建直接复制到构建后的目录。

4 如何使用 Webpack?

下面我们通过一个简单的例子来看一下 Webpack 的使用。这里假定你已经安装了最新版本的 Node.js 和 npm,因为使用旧版本可能会遇到各种问题。

1. 安装

创建 webpack-demo 目录,初始化 npm,并且在 webpack-demo 目录中安装 Webpack 和 webpack-cli:

  1. mkdir webpack-demo && cd webpack-demo

  2. npm init -y

  3. npm install webpack webpack-cli --save-dev

webpack-cli 用来在命令行中运行 Webpack 。这里建议本地安装 Webpack 和 webpack-cli,因为全局安装的话,Webpack 的升级会影响到所有的项目。

接下来我们先在项目中新增一些目录和文件:

  1. webpack-demo

  2. ├── package.json

  3. ├── dist

  4. ├── index.html

  5. └── src

  6. └── index.js

index.html 内容如下:

  1. webpack-demo

src/index.js 内容如下:

  1. function createEl() {

  2. var element = document.createElement('div')

  3. element.innerHTML = 'hello world'


  4. return element;

  5. }


  6. document.body.appendChild(createEl());

2. 第一次构建

在命令行运行:

  1. ./node_modules/.bin/webpack


  2. Hash: 2353b0d3d427eaa8a18a

  3. Version: webpack 4.29.6

  4. Time: 175ms

  5. Built at: 2019-04-03 22:08:36

  6. Asset Size Chunks Chunk Names

  7. main.js 1 KiB 0 [emitted] main

  8. Entrypoint main = main.js

  9. [0] ./src/index.js 175 bytes {0} [built]

大家可以发现,我们并没有在配置文件中指定打包的入口和输出的出口,也没有在命令行中指定配置参数,但可以看到在 ./dist 目录下新增了一个 main.js。这是因为 Webpack 配置中 entry 的默认值为 ./src,出口的默认目录是 ./dist。

  1. webpack-demo

  2. ├── package.json

  3. ├── dist

  4. | └── main.js

  5. ├── index.html

  6. └── src

  7. └── index.js

构建后的项目目录中新增了 main.js。

  1. webpack-demo

我们现在将 index.html 中的脚本引用修改为构建后的文件 ./dist/main.js,在浏览器预览,如果一切正常应该可以看到页面上会输出文本 hello world

3. 使用配置文件

对于简单的构建,Webpack 基本可以做到零配置。但对于复杂的单页应用而言,则需要使用 Webpack 的配置文件来提供个性化的功能。

首先我们在项目根目录下新增 webpack . config . js 文件:

  1. // webpack.config.js

  2. const path = require('path');


  3. module.exports = {

  4. entry : './src/index.js',

  5. output: {

  6. filename: 'bundle.js',

  7. path: path.resolve(__dirname, 'dist')

  8. }

  9. };

在配置文件中,通过 entry 指定了入口文件为 . /src/ index . js ,通过 output 指定了输出的目录为 ./ dist ,输出的文件名为 bundle . js 。目录结构更新如下:

  1. webpack-demo

  2. ├── package.json

  3. ├── Webpack .config.js

  4. ├── index.html

  5. ├── dist

  6. | └── bundle.js

  7. └── src

  8. └── index.js

同时为了调用简单,我们在 package.json 文件中设置快捷命令来调用 . /node_modules/ . bin / Webpack

  1. // package.json

  2. {

  3. "scripts": {

  4. "build": "webpack"

  5. }

  6. }

再次执行构建命令:

  1. npm run build

  2. > Webpack-demo@1.0.0 build C:\work\tech\webpack-demo

  3. > webpack


  4. Hash : d0fa6b1e011af414e622

  5. Version: webpack 4.29.6

  6. Time: 157ms

  7. Built at: 2019-04-03 22:42:50

  8. Asset Size Chunks Chunk Names

  9. bundle.js 1 KiB 0 [emitted] main

  10. Entrypoint main = bundle.js

  11. [0] ./src/index.js 175 bytes {0} [built]

index . html 中的 script 引用链接修改为 . /dist/ bundle . js ,在浏览器中预览页面,不出意外的话会输出文本 hello world

4. 使用插件

我们发现在构建的过程中,如果构建后的资源名称发生了变化,index.html 中对资源的引用会被动地跟着修改,非常不方便,我们引入 HtmlWebpackPlugin 来帮助我们自动生成入口文件,自动将生成的资源文件注入 index.html 中。

安装:

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

配置:

  1. const path = require("path");

  2. const HtmlWebpackPlugin = require("html-webpack -plugin");

  3. module.exports = {

  4. entry: "./src/index.js",

  5. output: {

  6. filename: "bundle.js",

  7. path: path.resolve(__dirname, "dist")

  8. },

  9. plugins : [new HtmlWebpackPlugin()]

  10. };

在配置文件中,我们引入插件,并在 plugins 选项中,将插件实例化后添加到数组中。该插件会自动生成 index.html,因此原目录中的 index.html 文件可以删除。

  1. webpack-demo

  2. ├── package.json

  3. ├── webpack.config.js

  4. ├── dist

  5. | └── bundle.js

  6. └── src

  7. └── index.js

再次执行构建命令:

  1. $ npm run build


  2. > webpack-demo@1.0.0 build C:\work\tech\webpack-demo

  3. > webpack


  4. Hash: 39dc7567ef99a69140e7

  5. Version: webpack 4.29.6

  6. Time: 1241ms

  7. Built at: 2019-04-03 22:53:44

  8. Asset Size Chunks Chunk Names

  9. bundle.js 1 KiB 0 [emitted] main

  10. index.html 182 bytes [emitted]

  11. Entrypoint main = bundle.js

  12. [0] ./src/index.js 175 bytes {0} [built]

命令执行后我们发现我们的 ./dist 下多了一个 index.html 文件,并且 index.html 中的资源引用被自动更新为了

5. 使用 loader 处理 css 文件

为了使 Webpack 可以处理 import 进来的 css 文件,我们需要安装并配置 style







请到「今天看啥」查看全文