https://webpack.docschina.org/api/
https://webpack.docschina.org/
使用webpack构建浏览器和服务器环境的应用(同构应用),即用一份代码分别编译为浏览器和服务器环境下的代码。
所以使用API和模块时需要考量两个环境是否都支持。
用于模块化开发项目,打包模块化JavaScript
entry入口
module一切文件皆模板
loader转换文件,把module原内容转换成新的
plugin注入钩子:webpack构建过程中广播对应事件,插件可以监听这些事情的发生
最后输出模块化的组合(chunk),一个chunk由多个module组成
·获取初始化参数:shell命令行+配置文件
开始编译:上一步得到参数初始化Compiler对象,加载所有配置的插件,通过执行run开始执行编译
确定入口:根据配置中的entry
编译模块:从入口出发,调用所有配置的Loader对模块进行翻译
解决依赖:具体的方法看webpack采用的模块机制,common.js、AMD、ESM
输出资源:根据依赖将多个module打包成一个chunk,再将其转换为文件加入输出列表。
完成输出:根据配置文件,输出到对应目录Compiler对象负责监听文件、启动编译
模块依赖:apply函数传入module.export对象
loader的apply方法传入Compiler对象
好处
- 将许多碎小文件打包成一个整体,减少单页面内的衍生请求次数,提高网站效率
- 将ES6的高级语法进行转换编译,以兼容老版本的浏览器
- 将代码打包的同时进行混淆,提高代码的安全性。
- 将模块化、或者支持其他先进语法的代码转译为浏览器可以运行的。
单页应用的流行,网页的功能和实现代码变得复杂、庞大、web开发向模块化进发
相比不打包直接浏览器运行,模块的依赖关系完全由文件的加载顺序决定,而webpack有优化措施
常见构建工具
构建:将源代码转换为可执行的JavaScript、css、HTML代码。
主要包括:代码转换(ts->js、scss->css等)、文件优化、代码分割、模块合并、自动刷新(监听本地源代码的变化,自动重新构建、刷新浏览器)、代码校验、自动发布。
换一种说法:验证JavaScript语法、CSS压缩、Sass编译等
Npm Script
任务执行者,允许在package.json文件里使用script字段定义任务
内置在Node.js中,无需依赖;但是功能过于简单。
提供了pre、和post两个钩子
补充:
package.json 中版本号 ^ 和 ~
波浪符号:~1.15.2,库会去匹配更新到1.15.x的最新版本,但是他不会自动更新到1.16.0
插入符号:^3.3.4,库会去匹配3.x.x中最新的版本,但是他不会自动更新到4.0.0。
语义版本号分为X.Y.Z三位,分别代表主版本号、次版本号和补丁版本号。当代码变更时,版本号按以下原则更新。
如果只是修复bug,需要更新Z位。
如果是新增了功能,但是向下兼容,需要更新Y位。
如果有大变动,向下不兼容,需要更新X位。
Grunt
有大量的插件封装了常见的任务,也能管理任务之间的依赖关系,自动化执行依赖的任务。写在配置文件Gruntfile.js里
集成度不高,需要写很多配置,无法做到开箱即用。相当于进阶版Npm
Gulp
基于流的自动化构建工具。
管理、执行任务,还支持监听文件、读写文件。只需要通过以下五个方法基本可以支持所有构建场景。
- gulp.task注册任务
- gulp.run执行任务
- gulp.watch监听文件变化
- gulp.src读取文件
- gulp.dest写文件
同时提供了一堆插件去处理流,流可以在插件之间传递
Grunt的加强版,增加一些功能,但是仍然集成度不高,需要写很多配置,无法做到开箱即用。
Fis3
百度的优秀国产构建工具
Webpack
实践一个最简单的webpack
(1)新建文件夹之后 init一个web项目
生成package.json文件(配置NPM以使我们能够下载JavaScript包:开发、生产使用)
以webpack为例,使用下载的JavaScript包,还需要再建立一个JavaScript文件 webpack.config.js,描述其使用,文件中require语法引入包
区别于typescript,项目根目录下tsconfig.json输入文件列表以及编译选项(这是单独使用typescript情况,不是与webpack并用,并用时候在webpack.config.js中module里引入rules)
管理依赖项:dependencies、devDependencies、peerDependencies
dependencies include utility libraries such as lodash, classnames etc and also the “main” libraries of your project.
peerDependencies : react, react-dom, styled-components, etc
devDependencies:
formatting libraries: eslint, prettier, …
bundlers: webpack, gulp, parceljs, …
babel and all its plugins
everything related to tests: enzyme, jest, …
a bunch of other libraries: storybook, react-styleguidist, husky, …
git submodule,git submodule很容易造成一个环境里多版本共存,更容易触发问题。
A文件中的devDependencies,对应开发A时候添加依赖包时候的npm i -D
当我们的包在开发时依赖另一个包的时候,我们应该把他们作为devDependencies来安装,这样他们就不会污染模块使用者的node_modules。后面实际执行用不到,所以不需要下载。npm i A不会下载devDependencies部分
不加-D时候是添加到dependencies
"devDependencies": {
"@types/node": "^15.6.0",
"typescript": "^4.2.4",
"webpack-dev-server": "^3.11.2",
"gulp": "3.9.0",
"del": "2.2.0"
},
"dependencies": {
"webpack-cli": "^4.7.0"
}
保存这个文件后,IDE将自动开始安装gulp和del。 若没有,请右击package.json文件选择Restore Packages。
peerDependencies的目的是提示宿主环境去安装满足插件peerDependencies所指定依赖的包,然后在插件import或者require所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,最终解决插件与所依赖包不一致的问题。A的peerDependencies会和B一起被下载
适用于同一个页面中只出现一个版本或一个实例的npm包
注意:NPM3反对同行的依赖(peer dependencies)
(2)安装webpack到本地项目
注意区分系统全局安装和局部安装
npm i -g webpack//全局
npm i -D webpack//局部 等同于package.json里面的devDependencies?
//通过@指定版本
npm i -D webpack@<version>//局部
推荐局部安装到本项目,原因是可防止不同项目以来不同版本的webpack而导致冲突
生成了node_module文件夹
注意webpack命令的有效地址和npm命令
(3)运行构建前需要将入口的HTML和JavaScript文件建立好
webpack.config.js(webpack执行构建会从该文件读取配置)文件如下
'use strict';
const path=require('path');
module.exports={
entry:'./src/index.js', //打包文件路径
output:{
path:path.join(__dirname,'dist'), //输出文件路径
filename:'bundle.js' //输出文件名
},
mode:'production'
};
规范地新建一个src文件夹
文件夹中新建index.js和hello.js文件(Webpack 本身只能处理 JavaScript 模块,这里我们还不引入loader)
(4)然后执行webpack命令构建,这里自己添加了一个npm script命名
生成dist文件夹
webpack是一个打包模块化JavaScript的工具,会从index.js出发,识别出源码中模块化导入语句,递归找出入口文件所有依赖,将所有依赖和入口打包到一个单独的文件中即./dis/bundle.js
//bundle.js
(()=>{"use strict";document.write("hello webpack")})();
基础
配置
配置方式
- 执行Webpack可执行文件时候,加入命令行参数(本质)
- webpack.config.js文件描述配置 --config webpack.config.js
注意一部分配置只能通过 webpack.config.js文件进行配置
配置项目
1、Entry模块的入口
context作为查找相对路径的根目录
entry:可以是字符串、数组、对象、函数。前两者只会生成一个 “main” chunk。对象则会生成以键为名的多个chunk。
动态Entry:异步、同步
项目有多个页面且每个页面都有一个入口,且入口数还在不断增多
entry:()=>{
return {
a:'./pages/a',
b:'./pages/b',
}
};
entry:()=>{
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
2、output输出配置对象
output是一个对象,属性是配置如何输出最终想要的代码的配置项
output包含输出配置的对象
输出文件名
有入口的chunk的output
output. filename, 用string写死
当多个Chunk,根据chunk的标识来区分输出文件
filename:'[ name ]. js'
filename:'[ hash:8 ]. js' 可以指定hash值的长度
无入口的chunk的output
chunkFilename只用于在运行中生成的chunk
即使用CommonChunkPlugin、使用import动态加载等的情况
内置变量
变量名 | 含义 |
---|---|
id | chunk的唯一标识,从0开始 |
name | |
hash | chunk的唯一标识的hash值 |
chunkhash | chunk内容的hash值 |
输出的路径
output. path输出文件放在本地的位置,string类型的绝对路径
一般通过node.js的path模块去获取绝对路径。webpack运行在node.js环境
异步加载的资源
webpack打包复杂项目时候,可能会有构建出的资源需要异步加载,就要把资源放在线上资源的对应的URL地址
发布到线上的html文件使用jsonp引入异步加载资源 url+ filename
涉及异步加载
output. crossOriginLoading配置异步插入的Script标签的crossorigin值
anonymous加载资源不会带上用户的cookie
use-credentials带cookie
构建导出库
构建被其他模块导入使用的库,搭配使用libraryTarget、library
library导出库的名称
libraryTarget配置以什么方式导出库,字符串的枚举类型。
导出的库可以支持多种配置导入:
var
commonJS方式导入使用
commonJS2
this
window
global
output.library=‘Name’
lb_code是指导出库的代码内容,那输出和使用
// var
// webpack输出代码
var Name=lb_code;
// 使用库的方法
Name.doSomething();
// commonJS方式导入使用
exports['Name']=lb_code;
require('library-name-in-npm')['Name'].doSomething();
// commonJS2
module.exports=lb_code;
require('library-name-in-npm').doSomething();
// this
this['Name']=lb_code;
this.Name.doSomething();
// window
window['Name']=lb_code;
window.Name.doSomething();
// global
global['Name']=lb_code;
global.Name.doSomething();
commonJS、commonJS2方式导入使用的时候,可以配置要导出的子模块
module.exports=lb_code['a'];
require('library-name-in-npm')===1;
3、Module配置处理模块的规则
rules
loader处理源文件
loader:用于资源加载并处理各种语言的转换/编译(例如将不同语言转换为javascript),导出一个函数——对资源文件进行处理后输出内容,类似于管道。
可以串联多个 loader,将返回值交给下一个 loader 继续处理
webpaack是运行在node之上的,一个loader就是一个node模块,这个模块需要导出一个处理函数。webpack也为loader提供了一些可以调用的API,例如source map,处理文件的上下文
根据应用场景,loader有同步异步之分,具体体现在内部实现上
写好的loader一般发布到远程npm,然后下载源码到node_module下面
选中文件+use
Webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换。
css文件
npm install style-loader css-loader --save-dev
原理:将CSS的内容用JavaScript里的字符串存储起来,在网页执行JavaScript时通过DOM操作,动态地向HTML的head标签中插入style标签。
然后配置webpack.config.js文件,增加modules中的规则
实现针对性的规则配置
'use strict';
const path=require('path');
module.exports={
entry:'./src/index.js', //打包文件路径
context:
output:{
path:path.join(__dirname,'dist'), //输出文件路径
filename:'bundle.js' //输出文件名
},
mode:'production'
modules:{
rules:[
//正则匹配到以css结尾的文件使用下面的loader
test:/\.css$/,
use:['style-loader','css-loader']
]
}
};
通过test、include、exclude三个配置项来选中Loader要应用规则的文件,除了正则表达式,也支持正则表达式的数组,数组各项代表|或
默认处理顺序是从后往前,先交给css-loader
可以通过enforce选项可以将一个loader的执行顺序提到最前pre,或者最后post
这样做会导致JavaScript文件变大且网页加载时间变长,可以通过webpack Plugin机制来实现单独输出CSS文件
图片文件也有file-loader
parse与noParse
noParse配置项可以让webpack忽略对没有采用模块化的文件的递归解析和处理,可以提高构建性能。
因为例如jQuery、chartjs等庞大又没有采用模块化标准(不含import、require、define,可以直接在浏览器中运行),解析他们耗时有没有意义
parse可以更细粒度地控制哪些模块语法被解析,精确到语法层面
parse:{
amd: false, // 禁用
commjs: false,
system: false,
harmony: false, // 禁用ES6 import/export
browserify: false,
}
因为webpack是以模块化JavaScript文件为入口的,所以内置了对模块化JavaScript的解析功能。
4、resolve寻找模块所对应的文件
配置webpack如何寻找模块所对应的文件
alias 文件路径简写
import Utility from '../../utilities/utility';
import Utility from 'Utilities/utility'; // 使用别名
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'), // 用Utilities代替后面的路径
}
可以在给定对象的键后的末尾添加 $,以表示精准匹配以xyz结尾的导入语句
alias: {
xyz$: path.resolve(__dirname, 'path/to/file.js')
}
mainFields 找取适合的代码
有些第三方库会针对不同的环境提供几份代码(ES5、ES6…),那么webpack在打包import导入的第三方包的时候会根据mainFields的顺序去选取导入的文件
mainFields: ["browser", "module", "main"]
查看第三方包的package.json 含有这些字段:
{
...
main: 'build/d3.Node.js',
browser: 'build/d3.js',
module: 'index',
...
}
extensions 导入文件的文件后缀
自动加入导入文件的文件后缀
extensions: [".js", ".json"]
先找file.js再找file.json
import File from '../path/to/file'
modules 配置查找第三方库的目录
webpack默认到node_module下查找
modules: ["node_modules"]
如果添加一个目录到模块搜索目录,此目录优先于 node_modules/ 搜索
modules: ['./src/components', "node_modules"]
import ‘./src/components/button’ import ‘.button’
5、plugins扩展功能:作用于整个构建过程
plugins是一个plugin数组
plugin:用于资源加载以外的其他打包/压缩/文件处理等功能
是一个函数,或者包含apply方法的对象:
apply 方法有一个参数 compiler,通过 compiler 可以给 webpack 编译打包过程中添加钩子
构造函数里面挂载两个结果回调函数,done、fail
通过钩子的回调函数 callback 拿到打包结果对象 compilation(通过compilation.assets 获取资源文件信息),然后对打包结果对象 compilation 进行修改
使用
模块加载器
扩展webpack功能,通过在构建流程中注入钩子函数来实现,几乎所有webpack无法实现的功能都可以找到开源的plugin解决。
涉及webpack.config.js文件的内容。
webpack运行中设计很多事件,plugin可以监听这些事件,在特定的时刻调用webpack提供的API
来实现对webpack现有功能的扩展,比如打包优化、文件压缩功能。
上面提到的输出单独的CSS文件
'use strict';
const path=require('path');
module.exports={
entry:'./src/index.js', //打包文件路径
output:{
path:path.join(__dirname,'dist'), //输出文件路径
filename:'bundle.js' //输出文件名
},
mode:'production'
modules:{
rules:[
//正则匹配到以css结尾的文件使用下面的loader
test:/\.css$/,
use:['style-loader','css-loader']
],
plugins:[
new ExtractTextPlugin({
filename: `[name]_[contenthash:8].css`
}),
]
}
};
然后安装新引入的插件
npm i -D extract-text-webpack-plugin
npm下载、require语法导入、webpack.config.js的plugins数组中配置注册
部分需要快速执行命令的,在package.json中注册script
plugins属性是一个数组,里面的每一项都是插件的一个实例,在实例化一个组件时可以通过构造函数传入这个组件支持的配置属性。
DevServer
启动一个HTTP服务器用于启动webpack,服务网页请求,并接收webpack发出的文件更变信号,通过webSocket协议自动刷新网页做到实时预览。
先安装:
npm i -D webpack-dev-server
开启后控制台显示:
project is running at http://localhost:8080/
访问这个网址就能获取项目根目录下的index.html文件
而生成的bundle.js的网址是 http://localhost:8080/bundle.js,所以需要在index.html文件中script引入bundle.js
监听的实现:DevServer会让webpack在构建出的JavaScript代码里注入一个代理客户端用于控制网页,网页和DevServer通过webSocket通信,DevServer在收到来自webpack的文件变化通知时,通过注入的客户端控制网页刷新。inline配置
来自webpack的文件:即entry本身和依赖的文件才会被webpack添加到监听列表里。上述index.html文件是脱离JavaScript模块系统的,不会被webpack探索到。
devServer.hot 模块热替换
默认会自动刷新整个页面来做实时预览
模块热替换:不重新加载整个网页的情况下,局部更新,默认关闭
启动DevServer的时候带上–hot参数
或者dev.Server.hot配置
devServer.inline代理客户端自动注入
实时预览功能依赖一个注入页面的代理客户端,取接收来自devServer的命令并刷新网页的工作。
devServer.inline配置是否将这个代理客户端自动注入将运行在页面中的chunk
不开启devServer.将无法直接控制要开发的网页,这时他会通过刷新iframe来实时预览
常用命令的背后
即package.json文件中的script
npm run dev
执行dev-server.js文件,关于该文件的了解看
使用express、http-proxy-middleware代理的中间件等实现本地服务器的搭建,注意这里是负责模拟后台的数据
==和webpack-dev-server到底有什么区别和联系?==好像会混用
webpack-dev-server
webpack官方提供的一个小型Express服务器。
webpack-dev-server 主要为静态文件提供web服务以及自动刷新和热替换(HMR)
通过websocket协议来告知浏览器更新文件,以实现实时的预览。
编辑src中的代码,保存后浏览器端会实时自动刷新。LiveReload技术
npm run build
执行build.js文件,控制编译过程
webpack与vue
目前主流的前端开发框架都采用webpack作为工程化工具
vue是框架,而webpack是打包工具,注意区别。
vue官方提供了一个快速搭建vue项目的脚手架:vue-cli,使用它能快速的构建一个web工程模板。
vue-cli里面默认继承了express、webpack.
快速体验一下vue-cli
?没有在总目录下看到package.json,查找之后每个模块下面有一个??