10分钟学会前端工程化(webpack4.0)
目录
一、概要
1.1、前端工程化
1.1.1、前端工程化的任务
1.2、前端工程化工具
1.2.1、Grunt
1.2.2、Gulp
1.2.3、Yeoman
1.3、WebPack
1.3.1、Webpack的特点
1.3.2、资源
1.3.3、工作流程
1.3.4、搭建WebPack开发环境
二、快速上手
2.1、创建一个项目或目录
2.2、初始化项目
2.3、安装webpack
2.4、创建目录与文件
2.5、使用webpack命令打包
2.6、运行
三、核心概念与执行过程
3.1、模块(Module)
3.2、入口(entry)
3.3、出口(output)
3.4、模块转换器(loader)
3.5、插件(plugins)
3.6、模式(mode)
3.7、代码块(Chunk)
3.8、WebPack执行过程
四、模块转换器Loader
4.1、loader特性
4.2、使用loader的三种方式
4.3、常见的loader
4.3.1、文件
4.3.2、JSON
4.3.3、转换编译(Transpiling)
4.3.4、模板(Templating)
4.3.5、样式
4.3.6、清理和测试(Linting && Testing)
4.3.7、框架(Frameworks)
4.4、raw-loader(文件原始内容转换器)
4.5、CSS Loader(样式处理)
4.5.1、安装
4.5.2、配置
4.5.3、定义样式与引用
4.5.4、打包运行
4.5.5、注意事项
4.6、sass-loader(加载和转译 SASS/SCSS 文件)
4.7、url-loader(路径处理器)
一、概要
1.1、前端工程化
随着前端的不断发展与壮大,前端变得越来越复杂,组件化、模块化、工程化、自动化成了前端发展中不可或缺的一部分,具体到前端工程化,面临的问题是如何提高编码->测试->维护阶段的生产效率。
前端工程化是使用软件工程的技术和方法来进行前端项目的开发、维护和管理。
前端工程化是依据业务特点,将前端开发的规范、流程、技术、工具、经验等形成规范并建立成一种标准的体系。
现在的项目可能会不停的迭代,发布就成了日常开发的一部分,前端不仅要保证功能还要保证性能,传统的一次次的发布效率会非常低,前端工程化一般都有会借助一些工具。
实现前端工程化的目的简单来说就是通过流程规范、自动化工具来提升前端的开发效率、性能、质量、多人协作能力以及开发体验,建立前端工程化是各个团队必经的成长过程。
1.1.1、前端工程化的任务
前端不仅要保证功能还要考虑性能,要减少http请求数量、压缩、合并、预处理、规范代码、清理、打包、转换等工作。
前端大部分情况下源代码无法直接运行,必须通过转换后才可以正常运行。构建就是做这件事情,把源代码转换成发布到线上的可执行 JavaScrip、CSS、HTML 代码,包括如下内容。
(1)、代码转换:TypeScript 编译成 JavaScript、SCSS 编译成 CSS 等。
(2)、文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
(3)、代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
(4)、模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
(5)、自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。
(6)、代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
(7)、自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。
构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力。
1.2、前端工程化工具
历史上先后出现一系列构建工具,它们各有其优缺点。由于前端工程师很熟悉 JavaScript ,Node.js 又可以胜任所有构建需求,所以大多数构建工具都是用 Node.js 开发的。
构建工具的主要功能就是实现自动化处理,例如对代码进行检查、预编译、合并、压缩;生成雪碧图、sourceMap、版本管理;运行单元测试、监控等,当然有的工具还提供模块化、组件化的开发流程功能。
如果把工具按类型分可以分为这三类:
(一)、基于任务运行的工具:Grunt、Gulp
它们会自动执行指定的任务,就像流水线,把资源放上去然后通过不同插件进行加工,它们包含活跃的社区,丰富的插件,能方便的打造各种工作流。
(二)、基于模块化打包的工具:Browserify、Webpack、rollup.js
有过 Node.js 开发经历的应该对模块很熟悉,需要引用组件直接一个 require 就 OK,这类工具就是这个模式,还可以实现按需加载、异步加载模块。
(三)、整合型工具:Yeoman、FIS、jdf、Athena、cooking、weflow
使用了多种技术栈实现的脚手架工具,好处是即开即用,缺点就是它们约束了技术选型,并且学习成本相对较高。
1.2.1、Grunt
Grunt([ɡrʌnt]作呼噜声) 生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用 Grunt 自动完成许多事,并且花费很少的代价。如果找不到你所需要的插件,那就自己动手创造一个 Grunt 插件,然后将其发布到 npm 上吧。
官网:https://gruntjs.com/
GitHub:https://github.com/gruntjs/
中文网:https://www.gruntjs.net/
对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。当你在 Gruntfile 文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工作。
Grunt 是老牌的构建工具,特点是配置驱动,你需要做的就是了解各种插件的功能,然后把配置整合到 Gruntfile.js 中,下面是配置例子:
[](javascript:void(0); "复制代码")
module.exports = function(grunt) {[
grunt.initConfig({
jshint: {
files: ['Gruntfile.js', 'src//.js', 'test//.js'],
options: {
globals: {
jQuery: true }
}
},
watch: {
files: ['<%= jshint.files %>'],
tasks: ['jshint']
}
});grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.registerTask('default', ['jshint']);
};
](javascript:void(0); "复制代码")
Grunt 缺点也是配置驱动,当任务非常多的情况下,试图用配置完成所有事简直就是个灾难;再就是它的 I/O 操作也是个弊病,它的每一次任务都需要从磁盘中读取文件,处理完后再写入到磁盘,例如:我想对多个 less 进行预编译、压缩操作,那么 Grunt 的操作就是:
读取 less 文件 -> 编译成 css -> 存储到磁盘 -> 读取 css -> 压缩处理 -> 存储到磁盘
这样一来当资源文件较多,任务较复杂的时候性能就是个问题了。
1.2.2、Gulp
Gulp(ɡʌlp狼吞虎咽地吃,吞咽)是一个基于流的自动化构建工具。 除了可以管理和执行任务,还支持监听文件、读写文件。
中文网:https://www.gulpjs.com.cn/
官网:https://gulpjs.com/
特点:
易于使用:通过代码优于配置的策略,Gulp 让简单的任务简单,复杂的任务可管理。
构建快速:利用 Node.js 流的威力,你可以快速构建项目并减少频繁的 IO 操作。
插件高质:Gulp 严格的插件指南确保插件如你期望的那样简洁高质得工作。
易于学习:通过最少的 API,掌握 Gulp 不太费力,构建工作尽在掌握:如同一系列流管道。
Gulp 被设计得非常简单,只通过下面5种个方法就可以胜任几乎所有构建场景:
通过 gulp.task 注册一个任务;
通过 gulp.run 执行任务;
通过 gulp.watch 监听文件变化;
通过 gulp.src 读取文件;
通过 gulp.dest 写文件。
Gulp 的最大特点是引入了流的概念,同时提供了一系列常用的插件去处理流,流可以在插件之间传递
Gulp 特点是代码驱动,写任务就和写普通的 Node.js 代码一样:
[](javascript:void(0); "复制代码")
var gulp = require('gulp'); var pug = require('gulp-pug'); var less = require('gulp-less'); var minifyCSS = require('gulp-csso');[gulp.task('html', function(){ return gulp.src('client/templates/*.pug')
.pipe(pug())
.pipe(gulp.dest('build/html'))
});gulp.task('css', function(){ return gulp.src('client/templates/*.less')
.pipe(less())
.pipe(minifyCSS())
.pipe(gulp.dest('build/css'))
});gulp.task('default', [ 'html', 'css' ]);
](javascript:void(0); "复制代码")
再一个对文件读取是流式操作(Stream),也就是说一次 I/O 可以处理多个任务,还是 less 的例子,Gulp 的流程就是:
读取 less 文件 -> 编译成 css -> 压缩处理 -> 存储到磁盘
Gulp 作为任务类型的工具没有明显的缺点,唯一的问题可能就是完成相同的任务它需要写的代码更多一些,所以除非是项目有历史包袱(原有项目就是基于 Grunt 构建)在 Grunt 与 Gulp 对比看来还是比较推荐 Gulp!
适用场景:
通过上面的介绍可以看出它们侧重对整个过程的控制管理,实现简单、对架构无要求、不改变开发模式,所以非常适合前端、小型、需要快速启动的项目。
1.2.3、Yeoman
Yeoman([ˈjoʊmən]自耕农,自由民; 义勇骑兵队成员,young+man)的目的不仅是要为新项目建立工作流,同时还是为了解决前端开发所面临的诸多严重问题,例如零散的依赖关系。
Yeoman是Google的团队和外部贡献者团队合作开发的,他的目标是通过Grunt(一个用于开发任务自动化的命令行工具)和Bower(一个HTML、CSS、Javascript和图片等前端资源的包管理器)的包装为开发者创建一个易用的工作流。
Yeoman是一个强健的脚手架与构建工具,库,及工作流程的组合,帮你网页开发者快速创建出漂亮而且引人入胜的网页程序,Yeoman帮助我们创建项目,提供更好的工具来使我们的项目更多样化。
Yeoman提供generator系统,一个generator是一个插件,在我们在一个完整的项目上使用‘yo’命令时,会运行该generator。通过这些官方的Generators,推出了Yeoman工作流,工作流是一个健壮、有自己特色的客户端堆栈,包含能快速构建漂亮的网络应用的工具和框架。Yeoman提供了负责开始项目开发的一切,没有任何让人头痛的手动配置。
Yeoman主要提供了三个工具:脚手架(yo),构建工具(grunt),包管理器(bower)。这三个工具是分别独立开发的,但是需要配合使用,来实现我们更高效的工作流模式。
小结:
在 Npm Script 和 Grunt 时代,Web 开发要做的事情变多,流程复杂,自动化思想被引入,用于简化流程;
在 Gulp 时代开始出现一些新语言用于提高开发效率,流式处理思想的出现是为了简化文件转换的流程,例如将 ES6 转换成 ES5。
在 Webpack 时代由于单页应用的流行,一个网页的功能和实现代码变得庞大,Web 开发向模块化改进。
这些构建工具都有各自的定位和专注点,它们之间既可以单独地完成任务,也可以相互搭配起来弥补各自的不足。 在了解这些常见的构建工具后,你需要根据自己的需求去判断应该如何选择和搭配它们才能更好地完成自己的需求。
经过多年的发展, Webpack 已经成为构建工具中的首选,原因是:
大多数团队在开发新项目时会采用紧跟时代的技术,这些技术几乎都会采用“模块化+新语言+新框架”,Webpack 可以为这些新项目提供一站式的解决方案;
Webpack 有良好的生态链和维护团队,能提供良好的开发体验和保证质量;
Webpack 被全世界的大量 Web 开发者使用和验证,能找到各个层面所需的教程和经验分享。
1.3、WebPack
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。
其官网的首页图很形象的画出了 Webpack 是什么,如下:
一切文件:JavaScript、CSS、SCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。
Webpack 具有很大的灵活性,能配置如何处理文件,大致使用如下:
[](javascript:void(0); "复制代码")
module.exports = { // 所有模块的入口,Webpack 从入口开始递归解析出所有依赖的模块[
entry: './app.js',
output: { // 把入口所依赖的所有模块打包成一个文件 bundle.js 输出
filename: 'bundle.js' }
}
](javascript:void(0); "复制代码")
1.3.1、Webpack的特点
把一切都视为模块:不管是 CSS、JS、Image 还是 HTML 都可以互相引用,通过定义 entry.js,对所有依赖的文件进行跟踪,将各个模块通过 loader 和 plugins 处理,然后打包在一起。
按需加载:打包过程中 Webpack 通过 Code Splitting 功能将文件分为多个 chunks,还可以将重复的部分单独提取出来作为 commonChunk,从而实现按需加载。
优点:
专注于处理模块化的项目,能做到开箱即用一步到位;
通过 Plugin 扩展,完整好用又不失灵活;
使用场景不仅限于 Web 开发;
社区庞大活跃,经常引入紧跟时代发展的新特性,能为大多数场景找到已有的开源扩展;
良好的开发体验。
缺点:
Webpack的缺点是只能用于采用模块化开发的项目。
上手比较难、对于新手而言需要经历踩坑的过程。
对于Server 端渲染的多页应用有点力不从心。
小结:
Webpack 特别适合配合 React.js、Vue.js 构建单页面应用以及需要多人合作的大型项目,在规范流程都已约定好的情况下往往能极大的提升开发效率与开发体验。
1.3.2、资源
官网:https://webpack.js.org/
github:https://github.com/webpack/webpack
中文网:https://www.webpackjs.com/
深入浅出webpack电子书:http://webpack.wuhaolin.cn/
1.3.3、工作流程
Webpack 是通过配置来实现管理,与 Grunt 不同的是它包含的许多自动化的黑盒操作所以配置起来会简单很多(但遇到问题调试起来就很麻烦),一个典型的配置如下:
[](javascript:void(0); "复制代码")
module.exports = { //插件项[
plugins: [commonsPlugin], //页面入口文件配置
entry: {
index : './src/js/page/index.js' }, //入口文件输出配置
output: {
path: 'dist/js/page',
filename: '[name].js' },
module: { //加载器配置
loaders: [
{ test: /.css/, loader: 'jsx-loader?harmony' },
{ test: /.scss/, loader: 'url-loader?limit=8192'}
]
}, //其它解决方案配置
resolve: {
root: '/Users/Bell/github/flux-example/src', //绝对路径
extensions: ['', '.js', '.json', '.scss'],
alias: {
AppStore : 'js/stores/AppStores.js',
ActionType : 'js/actions/ActionType.js',
AppAction : 'js/actions/AppAction.js' }
}
};
](javascript:void(0); "复制代码")
1.3.4、搭建WebPack开发环境
(1)、安装NodeJS
在用 Webpack 执行构建任务时需要通过 webpack 可执行文件去启动构建任务,所以需要安装 webpack 可执行文件。 在安装 Webpack 前请确保你的系统安装了5.0.0及以上版本的 Node.js。
去https://nodejs.org/下载安装
设置国内npm的镜像
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
使用时用cnpm代替npm
(2)、安装webpack
安装 Webpack 到全局
安装到全局后你可以在任何地方共用一个 Webpack 可执行文件,而不用各个项目重复安装,安装方式如下:
npm i -g webpack
cli:
所有cli参数:
View Code
要安装 Webpack 到本项目,可按照你的需要选择以下任意命令运行:
[](javascript:void(0); "复制代码")
# npm i -D 是 npm install --save-dev 的简写,是指安装模块并保存到 package.json 的 devDependencies安装最新稳定版
npm i -D webpack
安装指定版本
npm i -D webpack@
# 安装最新体验版本
npm i -D webpack@beta
二、快速上手
2.1、创建一个项目或目录
创建一个空项目或一个空目录,不一定需要使用IDE,这里我使用WebStorm
2.2、初始化项目
npm init -y (-y直接跳过提问阶段)
[](javascript:void(0); "复制代码")
name - 包名.[
version - 包的版本号。
description - 包的描述。
homepage - 包的官网URL。
author - 包的作者,它的值是你在https://npmjs.org网站的有效账户名,遵循“账户名<邮件>”的规则,例如:zhangsan [email protected]。
contributors - 包的其他贡献者。
dependencies / devDependencies - 生产/开发环境依赖包列表。它们将会被安装在 node_module 目录下。
repository - 包代码的Repo信息,包括type和URL,type可以是git或svn,URL则是包的Repo地址。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字
](javascript:void(0); "复制代码")
package.json详解
2.3、安装webpack
webpack4需要安装webpack-cli:
npm i webpack webpack-cli --save-dev
2.4、创建目录与文件
src/bar.js
[](javascript:void(0); "复制代码")
//定义模块 //部分依赖lodash中的join方法[
import {join} from 'lodash'//导出一个默认模块
export default function bar() { function component() { //创建DOM元素
var element=document.createElement("h2"); //使用join连接数组将结果写入元素的html中
element.innerHTML=join(['Hello','Webpack','!'],' '); return element;
} //在body中添加子元素
document.body.appendChild(component());
}
](javascript:void(0); "复制代码")
实现使用lodash的join 连接字符串,在网页中输出字符串
依赖lodash、npm安装lodash,在bar.js中import lodash的join方法,输出text
npm i lodash --save
src/index.js
[](javascript:void(0); "复制代码")
//入口文件[//导入自定义好的模块
import bar from './bar'; //调用
bar();
](javascript:void(0); "复制代码")
创建配置文件webpack.config.js
[](javascript:void(0); "复制代码")
//webpack配置文件[//依赖node中的path模块
const path=require('path'); //定义一个默认模块对象
module.exports={ //指定入口文件的位置
entry:"./src/index.js", //设置输出结果
output: { //路径,将相对路径转绝对路径
path:path.resolve(__dirname,'dist'), //文件
filename: "bundle.js" }
};
](javascript:void(0); "复制代码")
path.resolve获取文件的路径,_dirname为当前模块的绝对路径,详细解释如下:
View Code
index.html
webpack创建dist文件在dist中生成打包文件,然后再index.html中引用index.js文件
[](javascript:void(0); "复制代码")
[
Hello WebPack
Hello WebPack
](javascript:void(0); "复制代码")
2.5、使用webpack命令打包
可以指定配置文件
webpack --config webpack.config.js
也可以使用默认的配置文件
webpack
打包的结果:
View Code
bundle.js文件:
2.6、运行
三、核心概念与执行过程
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
从 webpack v4.0.0 开始,可以不用引入一个配置文件。然而,webpack 仍然还是高度可配置的。在开始前你需要先理解几个核心概念:
3.1、模块(Module)
在Webpack里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的Entry开始递归找出所有依赖的模块。
webpack把一切都视为模块,不管是 CSS、JS、Image 还是 HTML 都可以互相引用。Node.js 从最一开始就支持模块化编程。然而,在 web,模块化的支持正缓慢到来。在 web 存在多种支持 JavaScript 模块化的工具,这些工具各有优势和限制。webpack 基于从这些系统获得的经验教训,并将模块的概念应用于项目中的任何文件。
什么是 webpack 模块
对比 Node.js 模块,webpack 模块能够以各种方式表达它们的依赖关系,几个例子如下:
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- 样式(url(...))或 HTML 文件()中的图片链接(image url)
支持的模块类型
webpack 通过 loader 可以支持各种语言和预处理器编写模块。loader 描述了 webpack 如何处理 非 JavaScript(non-JavaScript) 模块,并且在 bundle 中引入这些依赖。 webpack 社区已经为各种流行语言和语言处理器构建了 loader,包括:
- CoffeeScript
- TypeScript
- ESNext (Babel)
- Sass
- Less
- Stylus
3.2、入口(entry)
入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。
入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。
每个依赖项随即被处理,最后输出到称之为 bundles 的文件中,我们将在下一章节详细讨论这个过程。
可以通过在 webpack 配置中配置 entry 属性,来指定一个入口起点(或多个入口起点)。默认值为 ./src。
接下来我们看一个 entry 配置的最简单例子:
[](javascript:void(0); "复制代码")
webpack.config.js[module.exports = {
entry: './path/to/my/entry/file.js' };
](javascript:void(0); "复制代码")
根据应用程序的特定需求,可以以多种方式配置 entry 属性。
多入口与多出口:
[](javascript:void(0); "复制代码")
{[
entry: {
app: './src/app.js',
search: './src/search.js' },
output: {
filename: '[name].js',
path: __dirname + '/dist' }
} // 写入到硬盘:./dist/app.js, ./dist/search.js
](javascript:void(0); "复制代码")
常用的占位:
- [hash]:模块标识符(module identifier)的 hash
- [chunkhash]:chunk 内容的 hash
- [name]:模块名称,key的名称,非文件名称
- [id]:模块标识符(module identifier)
- [query]:模块的 query,例如,文件名 ? 后面的字符串
3.3、出口(output)
输出结果,在 Webpack 经过一系列处理并得出最终想要的代码后输出结果。
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output 字段,来配置这些处理过程:
[](javascript:void(0); "复制代码")
webpack.config.js[const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'my-first-webpack.bundle.js' }
};
](javascript:void(0); "复制代码")
在上面的示例中,我们通过 output.filename 和 output.path 属性,来告诉 webpack bundle 的名称,以及我们想要 bundle 生成(emit)到哪里。可能你想要了解在代码最上面导入的 path 模块是什么,它是一个 Node.js 核心模块,用于操作文件路径。
示例:
3.4、模块转换器(loader)
模块转换器,用于把模块原内容按照需求转换成新内容。
loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理。
本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。
注意,loader 能够 import 导入任何类型的模块(例如 .css 文件),这是 webpack 特有的功能,其他打包程序或任务执行器的可能并不支持。我们认为这种语言扩展是有很必要的,因为这可以使开发人员创建出更准确的依赖关系图。
在更高层面,在 webpack 的配置中 loader 有两个目标:
- test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。
- use 属性,表示进行转换时,应该使用哪个 loader。
](javascript:void(0); "复制代码")
webpack.config.js[const path = require('path');
const config = {
output: {
filename: 'my-first-webpack.bundle.js' },
module: {
rules: [
{ test: /.txt$/, use: 'raw-loader' }
]
}
};module.exports = config;
](javascript:void(0); "复制代码")
以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:test 和 use。这告诉 webpack 编译器(compiler) 如下信息:
“webpack 编译器,当你碰到「在 require()/import 语句中被解析为 '.txt' 的路径」时,在你对它打包之前,先使用 raw-loader 转换一下。”
3.5、插件(plugins)
扩展插件,在 Webpack 构建流程中的特定时机注入扩展逻辑来改变构建结果或做你想要的事情。
loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务。
想要使用一个插件,你只需要 require() 它,然后把它添加到 plugins 数组中。多数插件可以通过选项(option)自定义。你也可以在一个配置文件中因为不同目的而多次使用同一个插件,这时需要通过使用 new 操作符来创建它的一个实例。
[](javascript:void(0); "复制代码")
webpack.config.js[const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
module: {
rules: [
{ test: /.txt$/, use: 'raw-loader' }
]
},
plugins: [ new HtmlWebpackPlugin({template: './src/index.html'})
]
};module.exports = config;
](javascript:void(0); "复制代码")
3.6、模式(mode)
通过选择 development 或 production 之中的一个,来设置 mode 参数,你可以启用相应模式下的 webpack 内置的优化
module.exports = {
mode: 'production' };
webpack4允许我们指定编译使用开发模式还是生产模式,这由mode这个配置来控制,value为枚举值:development/production,分别对应开发模式和生产模式(这个配置可以作为命令行的配置参数也可以作为配置文件中的一个配置项,默认值是production,即生产模式)。
源码还是不支持调试(都用eval函数包住),指定编译时的source-map生成方式,默认值是eval,可以解决问题。
3.7、代码块(Chunk)
一个 Chunk 由多个模块组合而成,用于代码合并与分割。
3.8、WebPack执行过程
Webpack 启动后会从 Entry 里配置的 Module 开始递归解析 Entry 依赖的所有 Module。 每找到一个 Module, 就会根据配置的 Loader 去找出对应的转换规则,对 Module 进行转换后,再解析出当前 Module 依赖的 Module。 这些模块会以 Entry 为单位进行分组,一个 Entry 和其所有依赖的 Module 被分到一个组也就是一个 Chunk。最后 Webpack 会把所有 Chunk 转换成文件输出。 在整个流程中 Webpack 会在恰当的时机执行 Plugin 里定义的逻辑。
Webpack从入口(entry)开始工作,通常这些是JavaScript模块,其中webpack开始其遍历过程。在此过程中,webpack会根据加载器配置评估入口(entry)匹配,这些配置告诉webpack如何转换每个匹配。
入口(entry)本身就是一个模块。当webpack遇到一个入口时,webpack会尝试使用入口的resolve配置将入口与文件系统匹配。除了node_modules之外,我们还可以告诉webpack对特定目录执行查找。也可以调整webpack与文件扩展名匹配的方式,并且可以为目录定义特定的别名。该耗竭与包章涵盖了更详细的这些想法。
如果解析通过失败,webpack会引发运行时错误。如果webpack设法正确解析文件,webpack将根据加载器定义对匹配的文件执行处理。每个加载器对模块内容应用特定的转换。
可以通过多种方式配置加载程序与已解析文件匹配的方式,包括文件类型和文件系统中的位置。Webpack的灵活性甚至允许我们根据文件导入项目的位置对文件应用特定的转换。
对webpack的加载器执行相同的解析过程。Webpack允许我们在确定应使用哪个加载器时应用类似的逻辑。由于这个原因,装载程序已经解析了自己的配置。如果webpack无法执行加载程序查找,则会引发运行时错误。
在实际应用中你可能会遇到各种奇怪复杂的场景,不知道从哪开始。 根据以上总结,你会对 Webpack 有一个整体的认识,这能让你在以后使用 Webpack 的过程中快速知道应该通过配置什么去完成你想要的功能,而不是无从下手。
下图可以简易的描述出webpack打包过程,该过程主要分为三个阶段:module构建、trunk构建和产出三个阶段:
四、模块转换器Loader
loader 用于对模块的源代码进行转换。loader 可以使你在 import 或"加载"模块时预处理文件。因此,loader 类似于其他构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件!
loader 是对应用程序中资源文件进行转换。它们是(运行在 Node.js 中的)函数,可以将资源文件作为参数的来源,然后返回新的资源文件。
4.1、loader特性
loader 支持链式传递。能够对资源使用流水线(pipeline)。一组链式的 loader 将按照相反的顺序执行。loader 链中的第一个 loader 返回值给下一个 loader。在最后一个 loader,返回 webpack 所预期的 JavaScript。
- loader 可以是同步的,也可以是异步的。
- loader 运行在 Node.js 中,并且能够执行任何可能的操作。
- loader 接收查询参数。用于对 loader 传递配置。
- loader 也能够使用 options 对象进行配置。
除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
插件(plugin)可以为 loader 带来更多特性。
loader 能够产生额外的任意文件。
loader 通过(loader)预处理函数,为 JavaScript 生态系统提供了更多能力。 用户现在可以更加灵活地引入细粒度逻辑,例如压缩、打包、语言翻译和其他更多。
loader 遵循标准的模块解析。多数情况下,loader 将从模块路径(通常将模块路径认为是 npm install, node_modules)解析。
loader 模块需要导出为一个函数,并且使用 Node.js 兼容的 JavaScript 编写。通常使用 npm 进行管理,但是也可以将自定义 loader 作为应用程序中的文件。按照约定,loader 通常被命名为 xxx-loader(例如 json-loader)。
4.2、使用loader的三种方式
(1)、配置(推荐):在 webpack.config.js 文件中指定 loader
module.rules 允许你在 webpack 配置中指定多个 loader。 这是展示 loader 的一种简明方式,并且有助于使代码变得简洁。同时让你对各个 loader 有个全局概览:
[](javascript:void(0); "复制代码")
module: {[
rules: [
{
test: /.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true }
}
]
}
]
}
](javascript:void(0); "复制代码")
Loaders需要单独安装并且需要在webpack.config.js中的modules关键字下进行配置,Loaders的配置包括以下几方面:
[](javascript:void(0); "复制代码")
test:一个用以匹配loaders所处理文件的拓展名的正则表达式(必须)[loader:loader的名称(必须)
include/exclude:手动添加必须处理的文件(文件夹)或屏蔽不需要处理的文件(文件夹)(可选)
query:为loaders提供额外的设置选项(可选)
](javascript:void(0); "复制代码")
(2)、内联:在每个 import 语句中显式指定 loader
可以在 import 语句或任何等效于 "import" 的方式中指定 loader。使用 ! 将资源中的 loader 分开。分开的每个部分都相对于当前目录解析。
import Styles from 'style-loader!css-loader?modules!./styles.css';
通过前置所有规则及使用 !,可以对应覆盖到配置中的任意 loader。
选项可以传递查询参数,例如 ?key=value&foo=bar,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}。
尽可能使用 module.rules,因为这样可以减少源码中的代码量,并且可以在出错时,更快地调试和定位 loader 中的问题。
(3)、CLI:在 shell 命令中指定它们
你也可以通过 CLI 使用 loader:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
这会对 .jade 文件使用 jade-loader,对 .css 文件使用 style-loader 和 css-loader。
4.3、常见的loader
4.3.1、文件
-
raw-loader
加载文件原始内容(utf-8) -
val-loader
将代码作为模块执行,并将 exports 转为 JS 代码 -
url-loader
像 file loader 一样工作,但如果文件小于限制,可以返回 data URL -
file-loader
将文件发送到输出文件夹,并返回(相对)URL
4.3.2、JSON
-
json-loader
加载 JSON 文件(默认包含) -
json5-loader
加载和转译 JSON 5 文件 -
cson-loader
加载和转译 CSON 文件
4.3.3、转换编译(Transpiling)
-
script-loader
在全局上下文中执行一次 JavaScript 文件(如在 script 标签),不需要解析 -
babel-loader
加载 ES2015+ 代码,然后使用 Babel 转译为 ES5 -
buble-loader
使用 Bublé 加载 ES2015+ 代码,并且将代码转译为 ES5 -
traceur-loader
加载 ES2015+ 代码,然后使用 Traceur 转译为 ES5 -
ts-loader
或awesome-typescript-loader
像 JavaScript 一样加载 TypeScript 2.0+ -
coffee-loader
像 JavaScript 一样加载 CoffeeScript
4.3.4、模板(Templating)
-
html-loader
导出 HTML 为字符串,需要引用静态资源 -
pug-loader
加载 Pug 模板并返回一个函数 -
jade-loader
加载 Jade 模板并返回一个函数 -
markdown-loader
将 Markdown 转译为 HTML -
react-markdown-loader
使用 markdown-parse parser(解析器) 将 Markdown 编译为 React 组件 -
posthtml-loader
使用 PostHTML 加载并转换 HTML 文件 -
handlebars-loader
将 Handlebars 转移为 HTML -
markup-inline-loader
将内联的 SVG/MathML 文件转换为 HTML。在应用于图标字体,或将 CSS 动画应用于 SVG 时非常有用。
4.3.5、样式
-
style-loader
将模块的导出作为样式添加到 DOM 中 -
css-loader
解析 CSS 文件后,使用 import 加载,并且返回 CSS 代码 -
less-loader
加载和转译 LESS 文件 -
sass-loader
加载和转译 SASS/SCSS 文件 -
postcss-loader
使用 PostCSS 加载和转译 CSS/SSS 文件 -
stylus-loader
加载和转译 Stylus 文件
4.3.6、清理和测试(Linting && Testing)
-
mocha-loader
使用 mocha 测试(浏览器/NodeJS) -
eslint-loader
PreLoader,使用 ESLint 清理代码 -
jshint-loader
PreLoader,使用 JSHint 清理代码 -
jscs-loader
PreLoader,使用 JSCS 检查代码样式 -
coverjs-loader
PreLoader,使用 CoverJS 确定测试覆盖率
4.3.7、框架(Frameworks)
-
vue-loader
加载和转译 Vue 组件 -
polymer-loader
使用选择预处理器(preprocessor)处理,并且require()
类似一等模块(first-class)的 Web 组件 -
angular2-template-loader
加载和转译 Angular 组件
4.4、raw-loader(文件原始内容转换器)
一个可以用于加载文件作为字符串使用的加载器,使用UTF-8编码。
安装
npm i --D raw-loader
安装结果:
用法一:
通过 webpack 配置、命令行或者内联使用 loader。
[](javascript:void(0); "复制代码")
webpack.config.js[module.exports = {
module: {
rules: [
{
test: /.txt$/,
use: 'raw-loader' }
]
}
}
](javascript:void(0); "复制代码")
在你的项目中
import txt from './file.txt';
用法二:通过命令行(CLI)
webpack --module-bind 'txt=raw-loader'
用法三:在你的项目中
import txt from 'file.txt';
内联使用
import txt from 'raw-loader!./file.txt';
示例:
webpack.config.json
View Code
src/file1.txt
A loader for webpack that lets you import files as a string.
src/bar.js
[](javascript:void(0); "复制代码")
//定义模块 //部分依赖lodash中的join方法[
import {join} from 'lodash'; //导入模块,获得file1.txt中的文件内容,被raw-loader处理
import message from './file1.txt'; //导出一个默认模块
export default function bar() { function component() { //创建DOM元素
var element=document.createElement("h2"); //使用join连接数组将结果写入元素的html中
element.innerHTML=join(['Hello','Webpack','!'],' ')+"
"+message; return element;
} //在body中添加子元素
document.body.appendChild(component());
}
](javascript:void(0); "复制代码")
运行结果:
内联使用模块处理器:
4.5、CSS Loader(样式处理)
webpack提供两个工具处理样式表,css-loader 和 style-loader,二者处理的任务不同,css-loader使你能够使用类似@import 和 url(...)的方法实现 require()的功能,style-loader将所有的计算后的样式加入页面中,二者组合在一起使你能够把样式表嵌入webpack打包后的JS文件中。
- css-loader: 加载.css文件
- style-loader:使用