透视前端工程化之 Webpack 基本介绍
透视前端工程化之 Webpack 基本介绍
1 Webpack 的特点
图片来源于网络
Webpack 是一款强大的打包工具。在 Webpack 中一切皆模块。Webpack 官网的 Banner 图完美地诠释了这一理念。Webpack 从一个入口文件开始递归地分析模块的依赖关系,根据依赖关系将这些模块打包成一个或多个文件。
目前几乎所有的前端构建和开发都是采用 Webpack 。因为 Webpack 有强大的社区生态,每月 Webpack 的下载量超过百万。通过 loader、plugin 支持 Webpack 与主流的前端框架和语言进行集成,比如 Vue、React、TypeScript。
- 支持所有的模块化 可以对 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 核心概念
入口
入口是 Webpack 进行构建的起点,Webpack 在构建过程中从入口文件开始,递归地编译模块,并分析模块间的依赖关系,最终得出依赖图。Webpack 依据该依赖图对模块进行组装,输出到最终的 bundle 文件中。
我们可以在 Webpack 的配置文件中配置 entry 属性,来指定入口文件,入口文件可以是一个也可以指定多个。
我们来看一个例子:
// Webpack .config.js module.exports = { entry: './src/app.js' };
配置多个入口的场景常见于多页应用中。如果配置多个入口可以这样:
// Webpack .config.js module.exports = { entry: { pageOne: './src/pageOne/app.js', pageTwo: './src/pageTwo/app.js' } };
输出
配置 output 选项可以指示 Webpack 如何去输出、在哪里输出我们的静态资源文件。
我们通过一个例子来看一下 output 如何使用:
// Webpack .config.js module.exports = { output: { filename: 'bundle.js', path: './dist' } };
上例中,我们指示 Webpack 最终的输出文件名为 bundle.js
,输出的目录为 ./dist
。
loader
loader 的使用
Webpack 本身是不能处理非 js 资源的,但我们却可以在 Webpack 中引入 css、图片、字体等非 js 文件。例如:
// app.js import Styles from './styles.css';
那么 Webpack 是如何实现的呢?
Webpack 中使用 loader 对非 js 文件进行转换。loader 可以在我们 import
或者加载模块时,对文件进行预处理,将非 js 的文件内容,最终转换成 js 代码。
loader 有三种使用方式:
- 配置 在 Webpack .config.js 文件中指定
- 内联 在每个
import
语句中线上指定 - CLI 在 shell 命令中指定。
在实际的应用中,绝大数都是采用配置的方式来使用,一方面在配置文件中,可以非常直观地看到某种类型的文件使用了什么 loader,另一方面,在项目复杂的情况下,便于进行维护。
我们通过一个简单的例子来看一下 loader 的使用:
// Webpack .config.js module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' } ] } };
我们需要告诉 Webpack 当遇到 css 文件的时候,使用 css-loader
进行预处理。这里由于 css-loader 是单独的 npm 模块,使用前我们需要先进行安装:
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 中注入
<style>
标签将 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 将文件提取到输出目录,并返回相对路径。
plugin
插件的使用
插件是 Webpack 的非常重要的功能,Webpack 本身也是建立在插件系统之上的。插件机制极大增强了 Webpack 的功能,为 Webpack 增加了足够的灵活性。通过插件,我们可以在 Webpack 的构建过程中,引入自己的操作,干预构建结果。
我们通过一个示例来看一下插件的使用:
// Webpack .config.js const HtmlWebpack Plugin = require('html-Webpack -plugin'); const Webpack = require('Webpack '); const config = { plugins: [ new Webpack .optimize.UglifyJsPlugin(), new HtmlWebpack Plugin({template: './src/index.html'}) ] }; module.exports = config;
示例中,我们用到了两个插件,一个是内置的 UglifyJsPlugin
插件,该插件对 js 进行压缩,减小文件的体积。一个是外部插件 HtmlWebpack Plugin
,用来自动生成入口文件,并将最新的资源注入到 HTML 中。
常用的插件
- HtmlWebpack Plugin 自动生成入口文件,并将最新的资源注入到 HTML 中。
- CommonsChunkPlugin 用以创建独立文件,常用来提取多个模块中的公共模块。
- DefinePlugin 用以定义在编译时使用的全局常量。
- DllPlugin 拆分 bundle 减少不必要的构建。
- ExtractTextWebpack Plugin 将文本从 bundle 中提取到单独的文件中。常见的场景是从 bundle 中将 css 提取到独立的 css 文件中。
- HotModuleReplacementPlugin 在运行过程中替换、添加或删除模块,而无需重新加载整个页面。
- UglifyjsWebpack Plugin 对 js 进行压缩,减小文件的体积。
- CopyWebpack Plugin 将单个文件或整个目录复制到构建目录。一个常用的场景是将项目中的静态图片不经构建直接复制到构建后的目录。
4 如何使用 Webpack
下面我们通过一个简单的例子来看一下 Webpack 的使用。这里假定你已经安装了最新版本的 nodejs 和 npm,因为使用旧版本可能会遇到各种问题。
4.1 安装
创建 Webpack -demo 目录,初始化 npm,并且在 Webpack -demo 目录中安装 Webpack 和 Webpack -cli:
mkdir Webpack -demo && cd Webpack -demo npm init -y npm install Webpack Webpack -cli --save-dev
Webpack -cli 用来在命令行中运行 Webpack 。这里建议本地安装 Webpack 和 Webpack -cli,因为全局安装的话,Webpack 的升级会影响到所有的项目。
接下来我们先在项目中新增一些目录和文件:
Webpack -demo ├── package.json ├── dist ├── index.html └── src └── index.js
index.html 内容如下:
<!doctype html> <html> <head> <title>Webpack -demo</title> </head> <body> <script src="./src/index.js"></script> </body> </html>
src/index.js 内容如下:
function createEl() { var element = document.createElement('div') element.innerHTML = 'hello world' return element; } document.body.appendChild(createEl());
4.2 第一次构建
在命令行运行:
./node_modules/.bin/Webpack Hash: 2353b0d3d427eaa8a18a Version: Webpack 4.29.6 Time: 175ms Built at: 2019-04-03 22:08:36 Asset Size Chunks Chunk Names main.js 1 KiB 0 [emitted] main Entrypoint main = main.js [0] ./src/index.js 175 bytes {0} [built]
大家可以发现,我们并没有在配置文件中指定打包的入口和输出的出口,也没有在命令行中指定配置参数,但可以看到在 ./dist 目录下新增了一个 main.js。这是因为 Webpack 配置中 entry 的默认值为 ./src,出口的默认目录是 ./dist。
Webpack -demo ├── package.json ├── dist | └── main.js ├── index.html └── src └── index.js
构建后的项目目录中新增了 main.js。
<!doctype html> <html> <head> <title>Webpack -demo</title> </head> <body> <script src="./dist/main.js"></script> </body> </html>
我们现在将 index.html 中的脚本引用修改为构建后的文件 ./dist/main.js,在浏览器预览,如果一切正常应该可以看到页面上会输出文本 hello world
。
4.3 使用配置文件
对于简单的构建,Webpack 基本可以做到零配置。但对于复杂的单页应用而言,则需要使用 Webpack 的配置文件来提供个性化的功能。
首先我们在项目根目录下新增 Webpack .config.js
文件:
// Webpack .config.js const path = require('path'); module.exports = { entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'dist') } };
在配置文件中,通过 entry
指定了入口文件为 ./src/index.js
,通过 output 指定了输出的目录为 ./dist
,输出的文件名为 bundle.js
。目录结构更新如下:
Webpack -demo ├── package.json ├── Webpack .config.js ├── index.html ├── dist | └── bundle.js └── src └── index.js
同时为了调用简单,我们在 package.json 文件中设置快捷命令来调用 ./node_modules/.bin/Webpack
。
// package.json { "scripts": { "build": "Webpack " } }
再次执行构建命令:
npm run build > Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo > Webpack Hash: d0fa6b1e011af414e622 Version: Webpack 4.29.6 Time: 157ms Built at: 2019-04-03 22:42:50 Asset Size Chunks Chunk Names bundle.js 1 KiB 0 [emitted] main Entrypoint main = bundle.js [0] ./src/index.js 175 bytes {0} [built]
将 index.html
中的 script 引用链接修改为 ./dist/bundle.js
,在浏览器中预览页面,不出意外的话会输出文本 hello world
。
4.4 使用插件
我们发现在构建的过程中,如果构建后的资源名称发生了变化,index.html 中对资源的引用会被动地跟着修改,非常不方便,我们引入 HtmlWebpack Plugin 来帮助我们自动生成入口文件,自动将生成的资源文件注入 index.html 中。
安装:
npm install --save-dev html-Webpack -plugin
配置:
const path = require("path"); const HtmlWebpack Plugin = require("html-Webpack -plugin"); module.exports = { entry: "./src/index.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "dist") }, plugins: [new HtmlWebpack Plugin()] };
在配置文件中,我们引入插件,并在 plugins 选项中,将插件实例化后添加到数组中。该插件会自动生成 index.html,因此原目录中的 index.html 文件可以删除。
Webpack -demo ├── package.json ├── Webpack .config.js ├── dist | └── bundle.js └── src └── index.js
再次执行构建命令:
$ npm run build > Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo > Webpack Hash: 39dc7567ef99a69140e7 Version: Webpack 4.29.6 Time: 1241ms Built at: 2019-04-03 22:53:44 Asset Size Chunks Chunk Names bundle.js 1 KiB 0 [emitted] main index.html 182 bytes [emitted] Entrypoint main = bundle.js [0] ./src/index.js 175 bytes {0} [built]
命令执行后我们发现我们的 ./dist 下多了一个 index.html 文件,并且 index.html 中的资源引用被自动更新为了 <script type="text/javascript" src="bundle.js"></script>
。
4.5 使用 loader 处理 css 文件
为了使 Webpack 可以处理 import 进来的 css 文件,我们需要安装并配置 style-loader
和 css-loader
。
npm install --save-dev style-loader css-loader
修改 Webpack 的配置如下:
const path = require("path"); const HtmlWebpack Plugin = require("html-Webpack -plugin"); module.exports = { entry: "./src/index.js", output: { filename: "bundle.js", path: path.resolve(__dirname, "dist") }, module: { rules: [ { test: /\.css$/, use: ["style-loader", "css-loader"] } ] }, plugins: [new HtmlWebpack Plugin()] };
如此一来,当 Webpack 匹配到后缀为 .css 的文件都会使用 css-loader 和 style-loader 进行处理。
接下来我们在 ./src 目录下新增一个样式文件 main.css
。在样式中,设置文本的字体颜色为红色。
// main.css div{color: red}
紧接着我们在 ./src/index.js 中引用 main.css:
import "./main.css"; function createEl() { var element = document.createElement("div"); element.innerHTML = "hello world"; return element; } document.body.appendChild(createEl());
执行构建命令:
$ npm run build > Webpack -demo@1.0.0 build C:\work\tech\Webpack -demo > Webpack Hash: f9fcb8cfd689f4b96ce6 Version: Webpack 4.29.6 Time: 2672ms Built at: 2019-04-03 23:24:40 Asset Size Chunks Chunk Names bundle.js 6.85 KiB 0 [emitted] main index.html 182 bytes [emitted] Entrypoint main = bundle.js [0] ./src/index.js 199 bytes {0} [built] [1] ./src/main.css 1.05 KiB {0} [built] [2] ./node_modules/css-loader/dist/cjs.js!./src/main.css 170 bytes {0} [built] + 3 hidden modules
在浏览器预览,不出意外字体的颜色已经变成了红色,打开浏览器调试工具,可以看到在 <head>
标签里插入了一个 <style>
标签。
<style type="text/css"> div { color: red; } </style>
通过以上完整的示例,我们演示了 Webpack 的核心的几个配置的使用方式,我们对 Webpack 的使用应该有了一个基本的认识。
Webpack 中还有很多其他有用的配置项,篇幅原因不做详细的介绍。大家可以查阅 官方文档 自行配置和练习。
总结
本节我们对 Webpack 进行了总体的介绍。借助 loader、Webpack 可以处理一切资源,JS 的、非 JS 的,都可以。通过插件,我们可以在 Webpack 的构建过程中的每个事件节点加入自己的行为,来影响 Webpack 的构建。对 Webpack 的使用有了认识,可以为我们搭建起项目的基本框架提供一个基础。
笔者有一个前端工程化的实践型课程刚刚上线——《透视前端工程化》。
以 Vue 为例,结合笔者在团队中的工程化实践,带领大家从零开始搭建一个脚手架,将搭建脚手架用到的技术点逐一拆解,希望大家看完后,每个人都对脚手架和工程化思想有个较深入地理解。
相信在学完本课程后,大家至少有以下几点收获:
- 对前端工程化有一个系统认知;
- 能独立设计一套前端工程化解决方案;
- 知识广度上有大幅提升;
- 进入更好的平台,获得更好的薪酬。
感兴趣的话,还望大家多多支持!
作者简介:
王超,现任快狗打车(原 58 速运)前端负责人。
先后任职于人人网、奇虎 360,8 年知名互联网工作经验。
从 0 到 1 组建了快狗前端团队,负责团队技术体系的搭建,形成了以 Webpack 和 Vue 为基础、 Node.js 中间层为补充的,自动化、工程化、组件化的快狗前端技术体系。
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Python爬虫入门教程 59-100 python爬虫高级技术之验证码篇5-极验证识别技术之二
@[toc] 图片比对 昨天的博客已经将图片存储到了本地,今天要做的第一件事情,就是需要在两张图片中进行比对,将图片缺口定位出来 缺口图片 完整图片 计算缺口坐标 对比两张图片的所有RBG像素点,得到不一样像素点的x值,即要移动的距离 def get_distance(self,cut_image,full_image): # print(cut_image.size) threshold = 50 for i in range(0,cut_image.size[0]): for j in range(0,cut_image.size[1]): pixel1 = cut_image.getpixel((i, j))
- 下一篇
Java编程初学者应该了解的编程框架
动力节点Java培训最新上线Java实验班,等你来测试自己适不适合学习Java编程哦! 很多的Java初学者从前辈的口中和各种资料中经常会听到一个词:Java框架,那么什么是“Java框架”?Java框架又包含哪些内容?今天小编为大家解答一下什么是Java的框架,主流的Java框架有哪些。 什么是Java框架 所谓的Java框架,简单理解是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计、协作构件之间的依赖关系、责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方法,它为构件复用提供了上下文(Context)关系。 常用的Java框架有哪些 Struts、Hibernate和Spring是我们Java开发中的常用框架,他们分别针对不同的应用场景给出最合适的解决方案。但你是否知道,这些知名框架最初是怎样产生的? 我们知道,传统的JavaWeb应用程序是采用JSP+Servlet+Javabean来实现的,这种模式实现了最基本的MVC分层,使的程序结构分为几层,有负责前台展示的JSP、负责流程逻辑控制的Servlet以及负责数据封装的Javabean。但是这种结构仍然存在...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- Mario游戏-低调大师作品
- 2048小游戏-低调大师作品
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- Red5直播服务器,属于Java语言的直播服务器
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库