1 webpack介绍
webpack是一个开源的前端打包工具,Webpack 提供了前端开发缺乏的模块化开发方式,将各种静态资源视为模块,并从它生成优化过的代码。如:将浏览器无法识别的es6代码转换成es5、sass和less等css框架进行转换成css文件、通过使用pollify解决浏览器兼容等问题。
2 配置文件的作用
配置文件主要是告诉webpack那个文件为打包入口(entry)、向何处输出改文件(output),在输出的过程中需要通过什么插件帮忙转换和处理代码(loader和plugin)等等,下面直介绍部分字段的含义,具体的可参照官网。
2.1 webpack.config.js
{
//mode: "development", 设置当前的运行环境的标识
//context: "" 当前执行文件的工作目录,不写时默认为当前webpack.config.js所处的目录
entry:"./src/main.js", //配置打包文件
//entry:{ "main": "./src/main.js" }, 为对象的时候可以定义输出的文件名,在output的时候可以通过"[name].js"方式动态生成
//entry: ["babel-polyfill", "./src/main.js] 为数组的时候它会将三个文件整合到一个路口文件中
output: {
path: path.resolve(__diname, "./dist") //指定文件需要输的文件夹,即文件会被打包到当前文件所在目录(__dirname为node提供的当前文件所在的目录)下的dist文件夹中. path.resolve为node的path模块,resolve会返回一个绝对路径
filename: "[name].js",//[name]为entry中指定的文件名生成对应的文件,如果没有配置则会输出bundle.js
//publicPath: "./" 该参数为引用资源的路径,如果配置为/assets,则打包后的引用资源的路径会加上/assets,配置为"./"表示会引用当前了解下的资源
//library: "libaryName", 打包资源被引用的名称,打包后当用script标签方式引入的时候可以通过libaryName来访问到,如果没有定义则相当于执行一段立即执行函数方法(function() { //你的模块内容})(),同时输出的类型取决于libraryTarget
//libraryTarget: "umd" | "window" | "var" ... umd打包后的文件可以支持commonJS和AMD的方法来引入, 值为window的时候相当于windwo[library] = module 值为var相当于library = module
},
//module: {
//rules: [
//{
//test: 正则表达式,用于匹配需要转换的文件
//use: [ "style-loader", { loader: "css-loader", options: {} } ] // 这里可以是一个字符串数组也可以同时包含字符串和对象,为对象的时候可以设置额外的条件
//}
//]
//}
devServer: {
//除了在该文件配置外也可以在package.json中通过脚本执行这里的port在脚本中对应的书写方式为 --port 8080 其他的类似在属性的前面加上--即可
port: 8080, //启动服务后监听的端口
hot: true //是否启用热更新
contentBase: "./public/" //本地html文件路径。启动后webpack会将该文件打包到虚拟路径中,打开http://localhost:8080访问到的html文件就是这里指定的文件夹下的index.html
//其他配置可去webpack查询这里就不一一讲解
},
//插件,先简单介绍一下这里的插件其实都是一个个类,通过new的方式来使用插件,每个插件都是通过插件中apply方法被调用,后续自定义插件会讲到
plugins: [
//new htmlWebpackPlugin({
//template: path.resolve(__dirname, "./public/index.html") 指定需要打包的文件路径
//filename: "filename" 打包后的文件名
//inject: "body" | "head" js文件插入在文档的那个位置
//chunks: [] 指定需要插入到文本的js文件,对应entry中的key值,如果只有一个入口文件可不写这个参数
//}) 这个插件是指定的html文件给进行打包输出
],
resolve: {
extensions: [".js", ".json"], //自动补全文件的后缀,从左到右匹配,越左边优先级越高
alias: {
//别名, 类似于vue中的@,给@配置对应的地址来减少目录查找的层数
"@": "./src",
}
}
}
2.2 package.json
{
{
"name": "webpack", //当我们需要打包模块发不到npm上的时候,当你需要引入时这个就是import form “name” 中的引用名
"version": "1.0.0", //版本
"description": "",
"main": "index.js", //入口文件, 就是指定当引入使用这个模块的时候import form “name” 是那个打包后的文件作为入口
"scripts": {
"dev": "webpack-dev-server --config webpack.config.js", //用于启动webpack服务 需要先安装webpack-dev-server webpack-cli webpack
"build": "webpack --config webpack.config.js", //开始打包文件 --config是用来制定运行那个webpack文件,在vue中我们能够看到会分为webpack.pro.config.js和webpack.dev.config.js
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
//这里引用版本的时候前面会有^或者~
//^ --- 代表安装的时候使用5.x.x下的最新版本, 如:当最新版本为5.6.0 而下方配置5.2.0的时候运行npm i 会安装5.6.0的版本,安装的版本不会超过5
//~ --- 代表安装的时候使用5.1.x下的最新版本, 如:当最新版本为5.1.9 而下方配置5.1.1的时候运行npm i 会安装5.1.9的版本,安装的版本不会超过5.1
//不带符号的时候安装的就是指定的版本
"webpack": "^5.0.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
},
}
}
3 自定义loader
3.1 介绍
loader主要用来处理对资源文件的解析,调用他的前提是你的入口文件有引入(通过import等方法)然后被定义的正则表达式所匹配到(test字段)。然后webpack会从右到左依次调用use字段里的每一个loader。
module: {
rules: [
{
test: 正则表达式,用于匹配需要转换的文件
use: [ "style-loader", {
loader: "css-loader", options: {
} } ] // 这里可以是一个字符串数组也可以同时包含字符串和对象,为对象的时候可以设置额外的条件
}
]
}
3.2 基本方法介绍
一个loader就是一个方法,在编写loader的时候要确保每一个loader最好只处理一件事情,比如css-loader主要是处理在js文件中通过import引入css文件,进行转换。style-loader主要是将被css-loader处理过的css插入到html文档中。
/**
@param {Buffer | String} source 一般都是文件内容
@param { sourceMap } map 用于把转换后的内容得出原内容的 Source Map,方便调试
@param { any } meta 其它信息
*/
//方式一同步调用
module.exports = function(source, map, meta) {
//最终需将source返回
return source
}
//方式二异步调用
module.exports = function(source, map, meta) {
//最终需将source返回
const cb = this.async()
setTimeout(() => {
/**
cb(err, source, sourceMap, abstractSyntaxTree)
err | source 必填
sourceMap | abstractSyntaxTree 可选
// 如果本次转换为原内容生成了 AST 语法树,可以把这个 AST 返回,
// 以方便之后需要 AST 的 Loader 复用该 AST,以避免重复生成 AST,提升性能
abstractSyntaxTree?: AST
*/
cb(null, source)
})
}
3.3 调用的时机
在webpack-dev-server模式下开启hot模式后每一次文件的更新都会调用一次
在构建的时候当然只会调用一次
3.4 案例一(转换未知文件内容)
3.4.1 目录
-root
--src
--loader
--my-loader.js
--index.js
--c.tcss
--package.json
--webpack.config.js
3.4.2 各文件内容
webpack.config.js
const path = require("path")
module.exports = {
entry: {
"main": "./src/index.js"
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.tcss$/, //匹配.tcss后缀的文件
use: [ 'style-loader', 'css-loader', 'my-loader' ] //从右到左依次执行loader
}
]
},
resolveLoader: {
//原本我们需要将loader发布到npm后通过npm i将loader安装后才能被识别
//这个参数可以告诉webpack可以去./src/loader目录下和node_modules目录下查找对应的loader名文件
modules: [ path.resolve(__dirname, "./src/loader"),'node_modules' ]
}
}
package.json
{
"name": "webpack",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --config webpack.config.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"css-loader": "^3.4.0",
"style-loader": "^1.3.0",
"webpack": "^4.9.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
},
}
c.tcss
// 这里的add方法是我们需要处理的 我们将得到最后的结果后将资源返回给css-loader处理
.main {
width: 100px;
height: add(100,200,"px");
background: red;
}
index.js
import "./c.tcss"
my-loader.js
module.exports = function(source, map, meta) {
const regx = /add\((.*)\)/g
// 通过正则匹配到add()方法以及括号里的内容然后在这里进行数据的相加和拼接操作后返回
let _source = source.replace(regx, (t, x, z) => {
const _l = x.split(",")
let total = 0
for(let i = 0; i < _l.length; i++) {
if(i == _l.length - 1) {
_l