自定义loader
- loader就是一个函数
- 获取参数的方式
this.query
const options = loaderUtils.getOptions(this);
module.exports = function(source){
return source.replace("hello", "hello world");
}
module:{
rules: [
test: /\.js/,
use:[path.resolve(__dirname, './loaders/replaceLoader.js')]
]
}
module:{
rules: [
test: /\.js/,
use:[{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
options: {
name: 'haha'
}
}]
}
module.exports = function(source){
return source.replace("hello", this.query.name);
}
可以在自定义loader中通过loader-utils插件来分析和获取options传递的参数
npm i loader-utils --save-dev
const loaderUtils = require('loader-utils');
module.exports = {
const options = loaderUtils.getOptions(this);
return source.replace('hello', options.name)
}
- 如果在自定义loader里需要写异步逻辑:
- replaceLoader.js就是之前同步将“hello” 替换成“hello world”的loader
- replaceLoaderAsync.js就是异步将‘hello’替换成‘haha’的loader
const loaderUtils = require('loader-utils');
module.exports = {
const options = loaderUtils.getOptions(this);
const callback = this.async();
setTimeout(()=>{
const result = source.replace('hello', options.name);
callback(null,result);
},1000)
}
- 想实现的是先将‘hello’替换成‘haha’,再将‘haha’替换成‘hello world’
module:{
rules: [
test: /\.js$/,
use:[{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
},
{
loader: path.resolve(__dirname, './loaders/replaceLoaderAsync.js'),
options: {
name: 'haha'
}
}
]
}
- 如果对于自定义loader引入时不想每个都写path.resolve(__dirname,'xxx'),借助webpack配置参数:resolveLoader
resolveLoader
resolveLoader:{
modules: ['node_modules', './loaders']
},
module:{
rules:[
test: /\.js$/,
use: [
{loader: 'replaceLoader'},
{loader: 'replaceLoaderAsync', options:{name:'haha'}}
]
]
}
自定义loader帮助实现的一些功能举例:
- 异常捕获
- 写jquery代码的时候要对前端异常代码进行监控,需要对代码进行异常捕获,需要对jquery底层源码进行修改,里面加一些try/catch这样的代码,同时对业务代码外层也要加try/catch来捕获代码异常,及时报到线上进行预警,这个时候异常代码就要侵入业务代码之中,会让业务代码看上去很乱;通过webpack,编写自定义loader就能实现这个功能,而不需要掺在业务代码中
- 通过抽象语法树对源代码进行分析,当发现有function(){}就替换成try(function(){})catch(e)这样的语法
- 国际化
- 网站要出中文版/英文版,通过占位符,加上自定义loader来实现,通过全局变量来识别要打包的是中文版还是英文版
- if(全局变量===“中文版”) source.replace('{{title}}','中文标题')
- source.replace('{{title}}','english title')
- 当发现源代码需要一些包装,就可以考虑使用loader来实现
自定义plugin
- plugin是一个类
- plugin的核心机制是事件驱动(发布订阅)设计模式,在这个模式里,代码运行是通过事件驱动的
举例:当打包结束,在dist目录下生成一个版权文件,里面写一些版权信息
class CopyrightWebpackPlugin {
constructor(options){
console.log('插件被使用了')
}
apply(compiler){}
}
module.exports = CopyrightWebpackPlugin;
const CopyrightWebpackPlugin = require('./plugins/copyright-webpack-plugin.js');
plugins: [
new CopyrightWebpackPlugin({name:"zhuzhu"})
]
class CopyrightWebpackPlugin {
constructor(){
console.log('插件被使用了')
}
apply(compiler){
compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin',(compilation,cb) => {
console.log(compilation.asstes);
compilation.assets['copyright.txt'] = {
source: function(){
return 'copyright by zhuzhu';
},
size: function(){
return 20
}
}
cb();
})
}
}
对于同步的时刻写法:例
compiler.hooks.compile.tap('CopyrightWebpackPlugin',(compilation) => {})
Library打包
libraryTarget:"umd"
library:"library"
libraryTarget:"umd"
引入方式
import library from 'library';
const library = require("library");
require(['library'],function(){});
想通过script标签引入这个库,并通过library这个全局变量来使用
<script src="library.js"></script>
如:library.math进行使用
-----通过配置: library:"library"
const path = require("path");
module.exports = {
mode:"production",
entry: "./src/index.js",
output:{
path: path.resolve(__dirname, "dist"),
filename:"library.js",
libraryTarget:"umd",
library:"library"
}
}
libraryTarget:"this",
library:"library"
externals:['lodash']
PWA
- pwa:如果第一次访问某个网站成功了,突然服务器意外挂了,再次访问这个网站时,它可以在本地有一份缓存,可以利用缓存将之前的页面展示出来
npm i http-server --save-dev
增加script
"start":"http-server dist"
只有要上线的代码需要pwa的处理
这个第三方插件可以实现这个pwa的功能:
npm i workbox-webpack-plugin --save-dev
const WorkboxPlugin = require('workbox-webpack-plugin');
plugins:[
new WorkboxPlugin.GenerateSW({
clientsClaim:true,
skipWaiting:true
})
]
在入口文件index.js中:
if('serviceWorker' in navigator) {
window.addEventListener('load', ()=>{
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
console.log('service-worker registed')
})
.catch(error => {
console.log('service-worker register error')
})
})
}