前言
大家好,之前出了一篇面试篇webpack入门,这篇文章继续介绍接下来更深入东西。
概览
- 如何载入自己的loader
- 使用loader-utils,schema-utils
- 编写自己的loader
- 扩展
如何载入自己的loader
讲道理大家都是直接import一个loader或者使用webpack内置的loader的。
如果调试自己的loader,应该如下写法:
//webpack.config.jsconst path = require("path");module.exports = { module: { rules: [ { test: /\.js$/, use: [ { loader: path.resolve("loader.js"), options: { test: 'apple' } } ] } ] }};复制代码
其实和正常载入loader一样,只是这里指向的是本地文件的路径。
path.resolve('loader.js') 得出路径
/Users/kev1nzh/Desktop/my/webpack/loader.js
使用单个loader
在使用一个loader的时候,loader会接收你正则匹配的资源文件(如上,所有js文件)的字符串。loader通过代码转化模块后,最后返回传递出去。复制代码
使用多个loader
-
当使用多个loader的时候,从传入loader数组的最后一个开始反向传入资源文件字符串。
-
最后一个loader接收最原始的资源文件字符串,转化后传入下一个lodaer。
-
中间的loader接收上一个loader,转化后传入下一个。
-
第一个loader最后接收转化,并传出所有loader处理完的资源文件字符串。
{ test: /\.css$/, use: [ { loader: 'css-loader' }, { loader: 'style-loader' }, ]}//style-loader接收所有css的文件,转化完再传给css-loader,转化完后再怼出来。复制代码
使用loader-utils,schema-utils
loader-utils, schema-utils是webpack的loader工具库,有很多便捷的方法可以调用。
const { getOptions,stringifyRequest, parseQuery } = require("loader-utils");const validateOptions = require("schema-utils");const schema = { type: "object", properties: { test: { type: "string" } }};module.exports = function(source) { //getOptions 用于在loader里获取传入的options,返回的是对象值。 const options = getOptions(this); // stringifyRequest转换路径,避免require()或impot时使用的绝对路径 stringifyRequest(this, "./test.js"); // Result => "\"./test.js\"" //parseQuery获取query参数的,这个很简单就不说啦 parseQuery('?name=kev&age=14') // Result => {name: 'kev', age: '14'} //验证参数的类型是否正确。 validateOptions(schema, options, "loader");};复制代码
编写自己的loader
总算到手写环节了!!!!
//webapck.config.jsconst path = require("path");module.exports = { entry: "./src", output: { path: path.resolve(__dirname, "dist"), filename: "package.js" }, mode: "production", module: { rules: [ { test: /\.js$/, use: [ { loader: path.resolve("loader.js"), options: { work: '996', sick: 'ICU', } } ] } ] }};复制代码
首先载入工具库,为了后续使用。
第一步先验证options是否符合类型,
第二步获取参数,然后替换传入的资源文件字符串。
//loader.jsconst { getOptions } = require("loader-utils");const validateOptions = require("schema-utils");const schema = { type: "object", properties: { work: { type: 'String' }, sick: { type: 'String' } }};module.exports = function(source) { const options = getOptions(this); validateOptions(schema, options, 'loader'); const {work, sick} = options; source = source.replace(/\[work\]/g, work).replace(/\[sick\]/g, sick); return `export default ${ JSON.stringify(source)}`;};复制代码
展示下要转换的js。
// src/index.jsconsole.log('工作[work] 生病[sick] 加班不规范 亲人两行泪');复制代码
最后在命令行,webpack!!!!!
扩展
webpack是如何运行的?
const index = require('./index');const console = require('./console');//index.jsconst axios = require('./scripts/debounce.js'');const moment = require('moment');// do something复制代码
- webpack会解析所有模块,如果模块中有依赖其他文件,那就继续解析依赖的模块。直到文件没有依赖为止。
- 解析结束后,webpack会把所有模块封装在一个函数里,并放入一个名为modules的数组里。
- 将modules传入一个自执行函数中,自执行函数包含一个installedModules对象,已经执行的代码模块会保存在此对象中。
- 最后自执行函数中加载函数(webpack__require)载入模块。
分离代码
// ./src/moment.jsconst moment = require('moment');console.log(moment().format('MMMM Do YYYY, h:mm:ss a'))// ./index.jsconst momentJs = require('./src/moment');console.log(123);复制代码
如上代码,我们打包一下试试看。
两个文件有依赖关系,所以打包后,都会把moment模块打包进去。SplitChunksPlugin
webpack4.x的分离代码方法,之前的CommonsChunkPlugin插件已被移除。 此模块开箱即用,默认情况下,它仅影响按需块,因为更改初始块会影响HTML文件应包含的脚本标记以运行项目。
webpack将根据以下条件自动拆分块:
- 可以共享新块或来自该node_modules文件夹的模块
- 新块将大于30kb(在min + gz之前)
- 根据需要加载块时的最大并行请求数将小于或等于5
- 初始页面加载时的最大并行请求数将小于或等于3
- 当试图满足最后两个条件时,首选更大的块。
让我们看下代码如何实现!
module.exports = { //... optimization: { splitChunks: { chunks: 'initial', //选择哪些模块需要优化, 参数为 all、async、initial minSize: 30000, // 要生成的块的最小数 maxSize: 0, //要生成的块的最大数 minChunks: 2, // 分割前共享模块的最小块数 maxAsyncRequests: 5, //按需加载时的最大并行请求数 maxInitialRequests: 3, // 入口的最大并行请求数 automaticNameDelimiter: '~', //指定生成文件名当中的分隔符 name: true, //拆分块的名称 cacheGroups: { //缓存组 vendors: { test: /[\\/]node_modules[\\/]/, priority: -10 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true } } } }};复制代码
好了这篇需要讲的东西已经结束了。
面试系列第一篇:
面试系列第二篇:
面试系列第三篇:
面试系列第四篇: