webpack学习笔记

一、 安装

1.npm init -y初始化目录

2.npm i webpack webpack-cli -D安装webpack。

可以执行npx webpack ./src/main.js --mode=production --mode=development进行打包指定的文件

二、 基本内容

配置webpack.config.js,后使用npx webpack可直接打包 配置css-loader,安装npm i css-loader style-loader -D,然后在配置文件的module rules中添加一个对象,test填写正则,匹配css文件,use表示要使用的loader。 处理less,npm i less less-loader -D

处理scss,npm i sass sass-loader -D

处理stylus,npm i stylus-loader -D

···

sass:不用写大括号和分号{};,stly:冒号都不用写
图片资源可以不用配置loader就可以加载,如果要设置小图片转base64,则配置rules,type:'asset',parser等。图片资源输出目录,则配置generator,filename使用绝对路径.
打包前清空dist目录,则在output中配置clean:true
处理字体图标资源,和图片资源类似,不过type配置为asset/resource,以及没有了转化base64的配置,音视频等同理。
js代码格式检查,配置eslint。

  1. .eslintrc.js配置文件示例
css 复制代码
    module.exports={
        parserOptions:{
            ecmaVersion:6,
            sourceType:'module',
            ecmaFeatures:{
                jsx:true
            }
        },
        rules:{
            semi:'warn'//禁止分号,'off'|0,'warn'|1,'error'|2,分别代表提示的三种等级。
        },
        extends:[]
    }
  1. eslint可继承的规则如:eslint:recommended,plugin:vue/essential,react-app

  2. 安装npm i eslint eslint-webpack-plugin -D

  3. 在配置文件中const ESLintPlugin=require('webpack-eslint-plugin'),然后在plugins中写详细配置

arduino 复制代码
 new ESLintPlugin({
            context:path.resolve(__dirname,'src')//配置要检查的目录
        })
  1. 配置.eslintignore来忽略dist等,主要使用vscode编辑器插件eslint时,在dist目录也会提示报错信息。

js代码兼容,使用babel

  1. 配置文件babel.config.js或.babelrc.js,后缀写json和不写都是可以的。
  2. 需要下载的包有babel-loader,@babel/core以及预设包 @babel/preset-env
  3. 在webpack配置文件中给js配置babel-loader,options可以写在loader下面,也可以单独写在babel配置文件中,主要内容是presets预设

处理html,装包html-webpack-plugin,配置中可使用template指定使用的html模板。

开发服务器,安装webpack-dev-server,并在webpack配置文件中增加devServer配置,通过npx webpack serve启动服务。

三、分开发模式和生产模式

  1. 新建config文件夹,将webpack.config.js分成两个文件,一个webpack.dev.js,一个webpack.prod.js
  2. 注意绝对路径(path.resolve(__dirname,'../src'))
  3. 开发模式的配置不需要输出路径
  4. 运行方式npx webpack serve --config ./config/webpack.dev.js
  5. 生产模式的配置不需要devServe,mode改为production
  6. 打包npx webpack --config ./config/webpack.prod.js
  7. 指令配置,在package.json中,增加script指令
json 复制代码
"start":"npm run dev"
"dev":"webpack serve --config ./config/webpack.dev.js",
"build":"webpack --config ./config/webpack.prod.js"

四、

  1. css文件原本是一同打包进css的,现需要单独打包成css文件,装包mini-css-extract-plugin 2.在配置文件中引入,并将style-loader改成MiniCssExtractPlugin.loader,最后在plugins中调用一下,可以指定filename

css兼容性处理

  1. 使用postcss,需要下载的包有postcss postcss-loader postcss-preset-env
  2. 在配置文件的css-loader后面增加配置
css 复制代码
{
    loader:'postcss-loader',
    options:{
        postcssOptions:{
            plugins:[
                'postcss-preset-env'
            ]
        }
    }
}
  1. 在package.json中备注需要兼容的浏览器列表
bash 复制代码
"browserslist":[
    "ie >= 8"
    ## 实际开发中常用的写法:
    "last 2 version",
    "> 1%",
    "not dead"
]
  1. 可以将css的loader封装成一个方法,在配置文件中
javascript 复制代码
function getStyleLoader(pre){
    return [
        MinicssExtraxtPlugin.loader,
        "css-loader",
        {
            loader:'postcss-loader',
            options:{
                postcssOptions:{
                    plugins:[
                        'postcss-preset-env'
                    ]
                }
            }
        },
        pre //传入后面使用的其他loader,如sass-loader
    ].filter(Boolean) //如果pre是undefined,则过滤掉
}
  1. css压缩,安装css-minimizer-webpack-plugin,使用方法可以同其他插件一样,也可以在webpack中新增配置项(1)
  2. html-webpack-plugin本身会压缩html文件

5.高级配置

  1. sourceMap

开发模式,在webpack配置文件中加入devtool:'cheap-module-source-map'

生产模式,值为source-map

提升打包速度

  1. hotModuleReplacement 仅开发模式

实际上就是在DevServer中加入hot:true,也是默认值 对于js,可以在main.js中加入下面代码,对于使用了vue-loader或react-hot-loader的项目,默认已经有这些功能了

arduino 复制代码
if(module.hot){
    // 是否有模块热替换的功能
module.hot.accept('./js/count')
}
  1. oneOf 开发生产皆可

对于loader,会遍历每一个rule项

使用oneOf,当匹配到一个rule项,就不会继续向下匹配了

css 复制代码
rules:[
    {
        oneOf:[...]
    }
]
  1. include、exclude 开发生产皆可

在处理js的rule中写

javascript 复制代码
 {
        test:/\.js$/,
       // 不能同时用
       // exclude:/node_modules/,//表示不处理node_module中的文件
       include:path.resolve(__dirname,'../src') ,//表示只处理src里的文件
        loader:'babel-loader',
               
},
  1. cache

主要是缓存eslint检查和babel编译结果

babel写法,在loader处配置options

arduino 复制代码
 options:{
    cacheDirectory:true,//开启babel缓存
    cacheCompression:false,//关闭缓存压缩
   }

对于eslint,则在插件调用的地方加入参数

lua 复制代码
 cache:true,
 cacheLocation:path.resolve(__dirname,'../node_modules/.cache/eslintcache')
  1. thead 对js多进程打包 开发生产皆可

对js处理的主要是eslint,babel,terser,每个进程启动大概需要600ms时间,建议大项目使用 获取cpu核数

ini 复制代码
const os=require('os')
const threads=os.cpus().length

需要下载thread-loader包

在babel-loader出,增加loader

css 复制代码
{
    loader:'thread-loader',
    options:{
        works:threads
    }
}

处理terser,需要现在配置文件中引入插件

javascript 复制代码
const TerserWebpackPlugin=require('terser-webpack-plugin')
...
new TerserWebpackPlugin({
    parallel:threads
})

处理eslint,直接在调用插件那里加入参数threads
webpack中可以加入一项optimization:{minimizer:[...内容同plugins,放一些压缩的插件]}

  1. tree shaking 一种说法,实际就是只打包引入的文件,如import {count} from 'count',依赖es6的模块化

  2. babel会产生很多辅助代码,这里避免产生重复的辅助代码,需要安装包@babel/plugin-transform-runtime,然后在写babel-loader 的地方添加options配置项plugins:[@babel/plugin-transform-runtime]

  3. 图片压缩 (这部分操作报错的原因暂未实际测试过)

需要下载插件image-minimizer-webpack-plugin,imagemin 还需要下载的包,压缩方式有有损压缩和无损压缩,下载的包也有所不同

  无损:  imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo
  有损:  imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo

然后在webpack配置中引入插件

csharp 复制代码
const ImageMinimizerPlugin=require('image-minimizer-webpack-plugin')
...
//在plugins中配置
new ImageMinimizerPlugin({
    minimizer:{
        implementation:ImageMinimizerPlugin.imageminGenerate,
        options:{
            plugins:[
                ["gifsicle",{interlaced:true}],
                ["jpegtran",{progressive:true}],
                ["optipng",{optimizationLevel:5}],
                ["svgo",{
                    plugins:[
                        "preset-default",
                        "prefixIds",{
                            name:"sortAttrs",
                            params:{
                                xmlnsOrder:"alphabetical"
                            }
                        }
                    ]
                }]
            ]
        }
    }
})

安装无损或有损的包时可能会报错。。。 安装成功,打包也可能会报错,提示缺少jpegtran.exe和optipng.exe,将对应exe放到nodemodules中对应文件夹后再次打包即可。

多入口,code split

  1. entry配置为对象,一个模块名对应一个路径,如main:'./main.js',output的filename配置为[name].js,则打包后会生成对应名称的js
  2. 对于不同文件引用的公共方法,会都打包一份,如果要将公共方法提出来,则配置optimization的splitChunks
ruby 复制代码
    optimization:{
        splitChunks:{
            chunks:'all',//对所有模块进行分割
            // 一些默认值
            // minChunks:1,//至少被引用一次才被分割
            //maxAsyncRequests:30,//并行加载的最大文件数,超过则合并至其他文件
            // minSize:2000,//分割代码的最小大小
            // minRemainingSize:0,//类似minSize,保证提取的文件大小不为0
            // maxInitialRequests:30,//入口js最大并行请求数量
            // enforceSizeThreshold:50000,//超过50kb强制单独打包
            // cacheGroups:{ // 分组,哪些模块要打包到一个组
               
            //     defaultVendors:{//组名
            // 这里面可以写上面的那些配置,表示覆盖上面的那些配置
            //         test:/[\\/]node_modules[\\/]/,//需要打包到一起的模块
            //         priority:-10,//权重,越大越搞
             //           name:'chunk-react',//打包出来的js文件的名称

            //         reuseExistingChunk:true,//如果当前chunk已包含从主bundle中拆分出的模块,则被重用,而不是生成新的
            //     },
            //表示把react和antd相关的代码单独打包为一个js文件
                    react:{
                        test:/[\\/]node_modules[\\/]react(.*)?[\\/]/,
                        name:'chunk-react',
                        priority:40
                    },
                     antd:{
                        test:/[\\/]node_modules[\\/]antd[\\/]/,
                        name:'chunk-antd',
                        priority:40
                    },
            // }

            // 修改配置
            cacheGroups:{
                default:{
                    minSize:0,//我们定义的文件太小了,所以要改到最小的文件体积
                    minChunks:2,
                    priority:-20,
                    reuseExistingChunk:true
                }
            }
        }
    }
  1. 按需加载,动态导入

比如,点击按钮触发的事件不需要一开始就加载,可以点击之后再加载

javascript 复制代码
ducument.getElementById('btn').onclick=function(){
    //import动态导入,会将动态导入的代码文件分割(单独打包为一个文件),在需要使用的时候自动加载
    import('./count').then(res=>{
        //加载成功
    }).catch(err=>{
       //加载失败 
    })
}

单入口

  1. 只需要配置optimization的splitChunks的chunks:'all'
  2. 对于打包后的文件命名,首先需要在import中这样写import(/* webpackChunkName: "math" */'./js/btn'),then(res=>{, 然后需要在output中配置 chunkFilename:'static/js/[name].js'

统一命名

  1. output的filename:'static/js/[name].js', chunkFilename:'static/js/[name].chunk.js', type:asset的资源命名assetModuleFilename:'static/media/[hash:10][ext][query]', 还有css的命名类似

preload,prefetch

  1. preload立即加载,prefetch空闲时加载,兼容性较低需注意
  2. 装包preload-webpack-plugin,报错则@vue/preload-webpack-plugin

使用插件

php 复制代码
const PreloadWebpackPlugin=require('@vue/preload-webpack-plugin')
...
new PreloadWebpackPlugin({
    rel:'preload',
    as:'script'
    //如果是prefetch,则只用写rel:'prefetch',不用写as
})

网络缓存,打包后hash值

由于文件1存在对文件2的引用,文件2的文件发生变化,hash也变化,导致文件1不得不变化,为了解决这个问题, 将引用时文件hash单独存放在一个runtime文件,文件1在runtime文件查找文件2的引用名,这样文件1不用变化,实现方法如下

javascript 复制代码
//在optimization中加入
runtimeChunk:{
    name:(entrypoint) => `runtime~${entrypoint.name}.js`
}

然后filename的hash改成contenthash

js兼容问题

  1. babel能处理箭头函数,点点点运算符等,但无法处理async,promise,includes等,这里使用code-js
  2. 安装npm i core-js,
  3. 全量加载在main.js中import 'core-js'
  4. 按需加载,在main.js中import "core-js/es/promise"
  5. 自动加载,在babel的配置文件中配置,无需在main.js中引入,注意多了一层中括号,注意这个兼容范围跟package.json中的browserslist有关
lua 复制代码
 presets:[['@babel/preset-env',{
    useBuiltIns:'usage',//按需加载自动引入
    corejs:3//corejs版本
 }]]

pwa 离线访问

  1. 装包workbox-webpack-plugin
  2. 配置文件中,
javascript 复制代码
const WorkboxPlugin=require('workbox-webpack-plugin')
...
new WorkboxPlugin.GenerateSW({
    //这些选项帮助快速启用serviceworkers
    //不允许遗留任何旧的
    clientsClaim:true,
    skipWaiting:true
})
  1. 需要在main.js中加入代码
javascript 复制代码
if("serviceWorker" in navigator){
    window.addEventListener("load",()=>{
        navigator.serviceWorker.register('/service-work.js').then(registration=>{
            console.log("SW registered:"+registration)
        }).catch(registrationError=>{
            console.log("SW registration failed:"+registrationError)
        })
    })
}

注意打开需要以dist为根服务器地址,不然会找不到资源

这里可以用npm i serve -g,然后serve dist

总结

  1. 提升开发体验
    · source map,让开发或上线的代码有更准确的错误提示
  2. 提升webpack打包构建速度
    · HotModuleReplacement,开发时只更新修改的部分
    · OneOf,让文件一旦被某个loader处理了,就不继续遍历,提升打包速度
    · Include/Exclude 排除或只检测某些文件,处理的文件更少,速度更快。
    · Cache对babel和eslint处理结果进行缓存,让第二次打包速度更快
    · thead,多进程处理babel和eslint任务
    3.减少代码体积
    · Tree Shaking 剔除了没有使用的多余代码,让代码体积更小
    · @babel/plugin-transform-runtime 插件对 babel 进行处理,让辅助代码从中引入,而不是每个文件都生成辅助代码,从而体积更小,
    · Image Minimizer对项目中图片进行压缩,体积更小,请求速度更快。(需要注意的是,如果项目中图片都是在线链接,那么就不需 要了。本地项目静态图片才需要进行压缩。)
  3. 优化代码运行性能
    · code split对代码进行分割成多个js 文件,从而便单个文件体积更小,并行加载js速度更快,并通过 import 动态导入语法进行按需 加载,从而达到需要使用时才加载该资源,不用时不加载资源。
    · Preload、prefetch 对代码进行提前加载,等未来需要便用时就能直接使用,从而用户体验更好
    · network cache 能对输出资源文件进行更好的命名,将来好做缓存,从而用户体验更好。
    · core-js 对js 进行容性处理,让我们代码能运行在低版本浏览器。
    · PWA能让代码离线也能访问,从而提升用户体验。

react配置

  1. eslintrc文件,还需要安装eslint-config-react-app
css 复制代码
extends:['react-app'],
parserOptions:{
    babelOptions:{
        presets:[
            //解决页面报错问题
            ['babel-preset-react-app',false],
            "babel-preset-react-app/prod"
        ]
    }
}
  1. babel-loader,test:/.jsx?$/
  2. babel需要安装预设包babel-preset-react-app,babel.config.js,react-app包含了core-js等,无需多余配置
vbnet 复制代码
presets:["react-app"]

注意使用babel-preset-react-app时,打包会报错,需要安装cross-env,然后配置package.json中的dev指令

json 复制代码
"dev":"cross-env NODE_ENV=development webpack serve --config ./config/webpack.dev.js"
  1. 安装 npm i react react-dom
  2. 在webpack配置中加入
css 复制代码
resolve:{
    //自动补全文件后缀
    extensions:['.jsx','.js','.json']
}

然后可以运行简单的react项目。 6. react的hmr

typescript 复制代码
devServer中hot:true
npm i -D @pmmmwh/react-refresh-webpack=plugin react-refresh
配置文件中
1.const ReactRefreshPlugin=require('@pmmmwh/react-refresh-webpack=plugin')
2.babel-loader的options中加入
plugins:[
    'react-refresh/babel'
],
3.在外层plugins中
new ReactRefreshPlugin()
  1. react devServer路由刷新404问题,需要在DevServer中加入配置historyApiFallback:true

生产模式配置

favicon.icon的显示,将public中资源复制到dist,下载插件copy-webpack-plugin

css 复制代码
const CopyPlugin=require('copy-webpack-plugin')
...
new CopyPlugin({
    patterns:[
        {
            from:path.resolve(__dirname,'../public'),
            to:path.resolve(__dirname,'../dist'),
            globOptions:{
            ignore:["**/index.html"]
             }
        }
    ]
})

合并生产和开发配置

在webpack.config.js中使用process.env.NODE_ENV获取当前是production还是development

sql 复制代码
const isProduction=process.env.NODE_ENV==='production'
1. output路径区分
2. babel-loader的plugins:[
    !isProduction&&"react-refresh/babel"
]
3. copy功能,MiniCssExtractPlugin在生产模式用
4.过滤数组用.filter(Boolean)
5. mode,devtool,minimizer
6. webpack配置的minimize:isProduction,表示是否需要压缩,为true的话minimizer选项才生效

使用antd的优化

因为antd使用的less,这里对less-loader做一些改造 在返回样式处理函数中

javascript 复制代码
const getStyleLoader=(pre)=>{
    ...
    pre&&{
        loader:pre,
        options:pre==='less-loader'?{
            //antd自定义主题色
            lessOption:{
                modifyVars:{
                    "@primary-color":"#1da57a",
                },
                javascriptEnabled:true
            }
        }:{}
    }
}
//注意main.js中应当引入antd的less样式

打包优化,splitChunk中进行分包,以及可以performance:false关闭性能分析,提升打包速度

vue编译

以vue3为例

  1. 安装vue-loader,并修改配置
javascript 复制代码
const {VueLoaderPlugin}=require('vue-loader')
...
{
    test:/\.vue$/,
    loader:'vue-loader'
}
...
new VueLoaderPlugin()
  1. 安装vue-style-loader,并将style-loader改为vue-style-loader
  2. eslint配置
vbnet 复制代码
root:true,
env:{
    node:true
},
extends:["plugin:vue/vue3-essential","eslint-recommended"],
parserOptions:{
    parser:"@babel/eslint-parser"
}
//需要下载包@babel/eslint-parser,eslint-plugin-vue
  1. babel配置
perl 复制代码
presets:["@vue/cli-plugin-babel/preset"]

需要下载包@vue/cli-plugin-babel

  1. 然后运行会提示vue某环境变量未定义,这里修改一下webpack配置
javascript 复制代码
const {DefinePlugin}=require("webpack")
...
//cross-env的环境变量是给打包工具使用的
//DefinePlugin的环境变量是给源代码使用的
new DefinePlugin({
    __VUE_OPTIONS_API__:true,
    __VUE_PROD_DEVTOOLS__:false
}}
  1. resolve:{ extensions:['.vue','.js','.json']}

element-plus

  1. 按需导入,参照官网配置
  2. 配置路径别名,在resolve中添加配置
bash 复制代码
alias:{
    "@":path.resolve(__dirname:'../src')
}

原理

loader

  1. pre:前置loader,normal:普通,inline:内联,post:后置,相同优先级loader从下到上,从右到左执行。
javascript 复制代码
{
    enforce:'pre',//或'post'
    test:/\.js$/,
    loader:'loader1'
}
  1. 注意inline loader的写法
javascript 复制代码
import Styles from 'style-loader!css-loader?modules!./style.css'
import Styles from '!style-loader!css-loader?modules!./style.css'//表示跳过normal loader
import Styles from '-!style-loader!css-loader?modules!./style.css'//表示跳过pre和normal loader
import Styles from '!!style-loader!css-loader?modules!./style.css'//表示跳过pre,post和normal loader
  1. 写一个loader

loader本质是一个函数

content是文件内容,map sourceMap,meta 别的loader传递的数据

javascript 复制代码
//loader.js
module.exports=function(content,map,meta){
    return content
}
//webpack.config.js
...
loader:'./loader/loader.js'
...
  1. 4种loader,同步、异步、raw、pitch
javascript 复制代码
// 同步loader
// module.exports=function (content){
//     console.log(content)
//     return content
// }

module.exports=function (content,map,meta){
    // callback第一个参数表示是否有错误
    // 第二个参数是处理后的内容
    // 第三个
    // 第四个给下一个loader的参数
    console.log(content)
    //如清除console.log的写法
    content.replace(/console\.log\(.*\);?/g,"")
   this.callback(null,content,map,meta)
}

===

javascript 复制代码
// 异步loader
module.exports=function (content,map,meta){
    console.log('异步loader')
    const callback=this.async()
    setTimeout(()=>{
     callback(null,content,map,meta)
    },1000)
   
}

======

javascript 复制代码
// raw loader,接收的content是buffer数据

module.exports=function (content){
    console.log(content)
//    this.callback(null,content,map,meta)
return content
}
module.exports.raw=true
// 另一种写法
// function loaderName(content){
// return content

// }
// loaderName.raw=true
// module.exports=loaderName

======

javascript 复制代码
// pitch loader
module.exports=function (content){
    console.log(content)
//    this.callback(null,content,map,meta)
return content
}
// pitch 方法的执行顺序在loader解析前,
// 如use:['loader1','loader2','loader3'],pitch方法执行顺序loader1>loader2>loader3,然后再执行loader解析
// 如果pitch2有return,则不会执行pitch3,loader2,loader3,只会执行pitch loader2前面的loader1
module.exports.pitch=function(){

}
  1. 一些loader中的api

this.async异步回调,返回this.callback,const callback=this.async()

this.callback(err,content,sourceMap?,meta?)

this.getOptions(schema),获取loader的option

this.emitFile(name,content,sourceMap)产生一个文件 this.utils.contextify(context,request)返回一个相对路径 this.utils.absolutify(context,request)返回一个绝对路径

javascript 复制代码
//schema.json:
{
    "type":"object",
    "properties":{
        "author":{
            "type":"string"
        }
    },
    "additionalProperties":false
}
//additionalProperties表示不能新增字段
//loader.js
const schema=require('./schema.json')
...
const options=this.getOptions(schema)
console.log(schema.author)

实现简易babel-loader

  1. 安装@babel/core @babel/preset-env
  2. 在webpack中配置对js使用自定义的loader文件
css 复制代码
  {
                test:/\.js$/,
                loader:'./loaders/babel-loader.js',
                options:{
                    presets:['@babel/preset-env']
                }
            }
  1. 新建babel-loader.js文件,babel中的方法可以参考官网
javascript 复制代码
const schema=require('./schema.json')
const babel=require('@babel/core')
module.exports=function(content){
    const callback=this.async()
    const options=this.getOptions(schema)
    babel.transform(content,options,function(err,result){
        if(err){
            callback(err)
        }else{
            callback(null,result.code)
        }
        
    })
}
  1. schema配置
json 复制代码
{
    "type":"object",
    "properties":{
        "preset":{
            "type":"array"
        }
    },
    "additionalProperties":true
}

实现file-loader

  1. loader写法
javascript 复制代码
const loaderUtils=require('loader-utils')

module.exports=function(content){
// 1.根据文件内容生成hash值文件名(借助webpack官方提供的处理文件名的方法)
const interpolateName=loaderUtils.interpolateName(this,"[hash].[ext][query]",{
    content
})
console.log(interpolateName)
// 2.将文件输出
this.emitFile(interpolateName,content)
// 3.返回module.exports="文件路径(文件名)"
return `module.exports="${interpolateName}"`
}
module.exports.raw=true
javascript 复制代码
 {
                test:/\.(png|jpe?g|gif)$/,
                loader:'./loaders/file-loader.js',
                type:'javascript/auto'//阻止webpack默认的asset去处理这些资源
                
            },

实现style-loader

ini 复制代码
module.exports=function(content){
    //直接使用style-laoder只能处理样式,不能处理样式中引入其他资源的问题
    //借助css-loader处理样式中引入其他资源的问题
    //问题是css-loader暴露了一段js代码,style-loader需要执行js代码,得到返回值
    const script=`
    const styleEL=document.createElement('style');
    styleEL.innerHTML=${JSON.stringify(content)};
    document.head.appendChild(styleEL)
    `
    return script
}
  1. 基于以上代码,要处理css-loader处理后的代码,首先注释掉script等内容
kotlin 复制代码
module.exports.pitch=function(remainingRequest){
    // remainingRequest返回两段绝对路径,用!分隔,一个css-loader的,一个css的
    // 1.绝对路径处理成两个相对路径
   const relativePath= remainingRequest.split('!').map(absolutePath=>{
        return this.utils.contextify(this.context,absolutePath)
    }).join('!')
    console.log(relativePath)

    const script=`
    import style from "!!${relativePath}"
    const styleEL=document.createElement('style');
    styleEL.innerHTML=style
    document.head.appendChild(styleEL)
    `
    // 终止后面loader
    return script
}

plugin 原理

  1. webpack打包过程会触发一系列tapable钩子事件

tap 可注册同步和异步钩子

tapAsync 回调异步

tapPromise promise方式异步

  1. 基本结构
javascript 复制代码
class Plugin1{
    constructor(options){
        this.options=options
        
    }
        apply(compiler){
        console.log('test apply')
        compiler.hooks.environment.tap('TestPlugin',()=>{
            console.log('test Env')
        })
        compiler.hooks.make.tap('TestPlugin',(compilation)=>{
            debugger;
            console.log(compilation)
            compilation.hooks.seal.tap('Test Plugin',()=>{
                console.log('seal')
            })
        })
    }
}
// node 调试
/**
 * "debug":"node --inspect-brk ./node_modules/webpack-cli/bin/cli.js"
 * package.json添加debug的命令,代码需要调试的地方加入debugger;浏览器控制台会出现node图标,点击会看到调试数据,可用于观测compilation结构
 */
相关推荐
王哈哈^_^38 分钟前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie1 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic2 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿2 小时前
webWorker基本用法
前端·javascript·vue.js
cy玩具2 小时前
点击评论详情,跳到评论页面,携带对象参数写法:
前端
qq_390161773 小时前
防抖函数--应用场景及示例
前端·javascript
John.liu_Test4 小时前
js下载excel示例demo
前端·javascript·excel
Yaml44 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事4 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶4 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json