博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面试官:你使用webpack时手写过loader,分离过模块吗?
阅读量:6348 次
发布时间:2019-06-22

本文共 4929 字,大约阅读时间需要 16 分钟。

前言


大家好,之前出了一篇面试篇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复制代码
  1. webpack会解析所有模块,如果模块中有依赖其他文件,那就继续解析依赖的模块。直到文件没有依赖为止。
  2. 解析结束后,webpack会把所有模块封装在一个函数里,并放入一个名为modules的数组里。
  3. 将modules传入一个自执行函数中,自执行函数包含一个installedModules对象,已经执行的代码模块会保存在此对象中。
  4. 最后自执行函数中加载函数(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        }      }    }  }};复制代码


好了这篇需要讲的东西已经结束了。

面试系列第一篇:

面试系列第二篇:

面试系列第三篇:

面试系列第四篇:

如果您有收获或者疑问请在下方评论,求赞!谢谢观看到这里。

转载于:https://juejin.im/post/5cb58fb6f265da03452bd070

你可能感兴趣的文章
如何在TortoiseSVN客户端设置提交前必须写日志
查看>>
死磕java concurrent包系列(五)基于AQS的条件队列把LinkedBlockingQueue“扒光”
查看>>
java jwt 如何设定过期时间
查看>>
iOS之自定义tabBar(简便方式)
查看>>
CentOS下jar包随系统启动
查看>>
微信引导下载
查看>>
30行python代码实现微博热点推送给微信群
查看>>
WebRTC 及点对点网络通信机制
查看>>
一句话设置UITextField、UITextview的字数限制和placeholder
查看>>
Java集合源码分析之基础(二):哈希表
查看>>
React新旧生命周期
查看>>
webpack4 高手之路 第四天
查看>>
indexedDB入门
查看>>
跨域的四种方式
查看>>
前端小报 - 201901 月刊
查看>>
Idea VM options
查看>>
使用Data URI Scheme优雅的实现前端导出csv
查看>>
centos6.8 安装nginx
查看>>
【Leetcode】101. 对称二叉树
查看>>
如何让自己看起来更专业?前端程序员必须了解的几个“词语”
查看>>