产生
模块化的兼容问题,以及文件过多,网络请求频繁请求,所有的前端资源都需要模块化(css、html)。所以,就需要设想一下,可以实现工作的思路。
1、文件可以编译ES6语言,解决兼容
2、打包成一个文件,解决网络请求过于频繁。同时支持css png的文件格式
前端模块打包工具
webpack、rollup、parcel
webpack 支持模块打包、模块加载器(loader)、代码拆分
webapck
webpack快速使用
1、初始化配置 yarn init
2、安装 yarn add webpack webpack-cli
3、运行命令 yarn webapck 会默认从src下的index.js 文件开始打包
4、配置文件之入口出口
//基本配置 入口 出口配置
var path = require("path")
module.exports = {
entry: "./src/main.js", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"output") //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
}
}
5、配置文件之工作模式 默认会启动production的模式
yarn webpack --mode development 模式下,自动优化打包速度,添加一写调试中用到的辅助
yarn webpack --mode none 最原始的打包
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.js", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"output") //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
}
}
webpack打包结果运行原理(重点多看复习)
通过bundle.js,看到里边整体生成的代码是一个立即执行函数,这个函数是webpack的工作入口,同时这个函数接受一个modules的参数,调用这个函数的时候传递进去了一个数组。数组里的每个元素都是一个参数列表相同的函数,这里的函数对应原代码里边的模块。见图
也就是说,每一个模块最终都会被包裹到这种函数当中,从而实现模块私有作用域。
立即执行函数代码,见图
通过上图得知立即执行函数里边定义了一个 installedModules 的对象,来存放我们加载过的模块。然后定义了一个 __webpack_require__的函数。这个函数就是加载模块的。然后在这个函数上挂载了一些数据和工具函数.m、.c、.d等等。最后在调用了这个函数如图所示
然后传进去一个为0的参数,加载这个模块,然后这个模块的ID 就是实际上就是上边数组中的元素下标,所以这里才是我们加载原代码的入口模块。
可以,通过浏览器单步调试,查看webpack的执行流程 在浏览器Sources下找到bundle.js然后在文件里边打上断点。如图所示
刷新浏览器,启动调试,进入立即执行函数。可以看到接受的参数就是模块对应的两个函数
跳过挂载的函数,然后,最后加载了ID为0的模块。然后进入__webpack_require__()这个函数内部。可以看到先去判断了这个模块有没有被加载过,加载过的话,就从缓存里边读取,没有的话,创建一个新的对象。
创建完对象,就直接调用了这个模块所对应的函数。同时,把刚刚创建的模块对对象、导出对象、__webpack_require__函数传了进去。(modelu.exports,module(刚刚创建的对象),module.exports(导出的对象),__webpack_require__(函数))。这样就可以在模块内部通过module.exports导出成员,使用__webpack_require__载入模块。
webpack资源模块加载
webpack不仅仅是js的模块打包工具,同样对css可以打包。
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"output") //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
}
}
因为webpack默认之打包js文件,所以会把所有的非js文件都当成js文件解析。然后就会报错如图所示。
报出错误的同时,也会提示,需要正对不同的文件需要安装不同的loader。安装css-loader以及style-loader。因为laoder的加载机制是从下向上,从左到右。所以先执行的放下边。
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist") //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
},
module:{
rules:[
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",
"css-loader",
]
}
]
}
}
css-loader的作用就是将css文件转化为一个模块。然后把js代码push到了一个exports的模块里边。
style-loader,是创建一个style标签然后把样式代码挂载到了页面
Webpack 导入资源模块
因为,不会为了css直接指定入口文件打包,最好还是通过import的方式在需要用的文件里边引入css文件。如图所示
Webpack 文件资源加载器
file-loader,webpack的图片路劲在没有这是的情况下,会默认从根路径引入。所以没有图片路径会没有"dist/"。因此需要在导出的output里边设置publicPath:"dist/",并且 / 不能省略。
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist"), //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
publicPath:'dist/' //默认"" 表示根目录
},
module:{
rules:[
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",l
"css-loader",
]
},
{
test:/.png$/,
use:"file-loader"
}
]
}
}
Webpack URL 加载器
除了file-loader的形式,表示路径以外,还可以通过Data URLs的方式表示图片。因为直接通过如图所示的的路径就显示了图片,这样就把图片转化为了代码。
通过上述,可以知道可以把所有的文件都可以转化成为代码的形式,可以使用url-loader,这样减少了减少了http请求。
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist"), //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
publicPath:'dist/' //默认"" 表示根目录
},
module:{
rules:[
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",l
"css-loader",
]
},
{
test:/.png$/,
// use:"file-loader"
use:"url-loader" //转化为了一个Data url 没有了具体的物理文件
}
]
}
}
如图所示:图片的路径就变为了代码转化的data url
最佳实践:小文件使用Data URLs,减少请求次数,大文件单独提取存放,提高加载速度。然后,通过配置url-loader的方式。代码所示
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist"), //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
publicPath:'dist/' //默认"" 表示根目录
},
module:{
rules:[
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",l
"css-loader",
]
},
{
test:/.png$/,
// use:"file-loader"
// use:"url-loader" //转化为了一个Data url 没有了具体的物理文件
use:{
loader:"url-loader",
options:{
limit:10*1024 //单位是字节 得到的就是10KB的大小,这样设置就会只是针对10KB一下的图片进行url-loader
}
}
}
]
}
}
在这种情况下使用url-loader的时候 必须安装file-loader,超出的文件还是会调用file-loader。如果没有下载file-loader的话,在运行的时候就会报错。
Webpack 常用加载器分类
1、编译转换类 css-loader;
2、文件操作类 file-loader
3、代码检查类 eslint-loader
Webpack 与 ES 2015
因为模块打包需要,所以默认处理import和export,但是并不能转换其他的es6以后的特性。所以需要额外的安装babel-loader 还需要依赖babel核心模块@babel/core 以及用于完成具体特性转换的插件集合@babel/preset-env
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist"), //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
publicPath:'dist/' //默认"" 表示根目录
},
module:{
rules:[
{
test:'.js$',
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
}
},
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",l
"css-loader",
]
},
{
test:/.png$/,
// use:"file-loader"
// use:"url-loader" //转化为了一个Data url 没有了具体的物理文件
use:{
loader:"url-loader",
options:{
limit:10*1024 //单位是字节 得到的就是10KB的大小,这样设置就会只是针对10KB一下的图片进行url-loader
}
}
}
]
}
}
webpack 只是打包工具,需要单独的配置加载器来完成编译转换代码
Webpack 加载资源的方式
1、遵循ES Modules标准的import 声明
2、遵循commonJS标准的require函数
3、遵循AMD标准的define函数和require函数
可以加载上边的js的方式,同时,loader也可以加载非js也会触发资源加载。
例如:
样式代码中的@import指令和部分属性中的url函数,还有HTMl代码中图片的标签src属性都可以触发资源加载,可以使用html-loader,加载图片的src,但是a链接的href属性需要单独配置,因为html-loader默认只是设置了img:src
var path = require("path")
module.exports = {
mode:'development', //工作模式的属性 production(默认) | none
entry: "./src/main.css", //入口文件 ./不能省略
output: {
filename:'bundle.js', //输出打包后的文件名称
path:path.join(__dirname,"dist"), //path 必须是一个绝对路径 借助node path模块 指定输出的文件夹
publicPath:'dist/' //默认"" 表示根目录
},
module:{
rules:[
{
test:'.js$',
use:{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
}
},
{
test:/.css$/, //正则匹配文件的路径
// use:'css-loader'
use:[
"style-loader",l
"css-loader",
]
},
{
test:/.png$/,
// use:"file-loader"
// use:"url-loader" //转化为了一个Data url 没有了具体的物理文件
use:{
loader:"url-loader",
options:{
limit:10*1024 //单位是字节 得到的就是10KB的大小,这样设置就会只是针对10KB一下的图片进行url-loader
}
}
},
{
test:/.html$/,
use:{
loader:'html-loader',
options:{
attrs:['img:src','a:href']
}
}
}
]
}
}
最后,几种方式汇总如图
Webpack 核心工作原理
在项目中都会散落着各种各样的代码集资源文件,webpack会找到其中一个js文件作为打包入口。然后通过入口文件中的引入模块路径,解析推断出这个文件所依赖的模块,然后解析每个资源模块对应的依赖,最后就形成了整个项目中所有依赖文件中的依赖关系。最后通过配置文件中的rules规则进行打包配置,然后进行打包最后形成bundle.js文件
Webpack 开发一个 Loader
实现一个markdown-loader 实现markdown的文件加载器,这样就可以直接在项目中直接导入markdown文件,