如何打造一个webpack的plugin

前言

前几天面试,面试官问打造一个webpack的plugin有思路吗,我愣住了,来写个文章记录一下。

正文

不清楚webpack是啥的可以去看看我的上一篇文章,记录的很详细,我们就直接简单铺垫下开始。

一、创建目录结构

我们创建一个WEBPACK-PLUGIN的目录,初始化后,安装webpackwebpack-cli。接着创建一些目录文件,结构如下:

image.png

二、编写index.js

我们在index.js中写一段很简单的代码,如下:

function add(a, b) {
  return a + b
}

add(1, 2)

console.log('hello world');

如果这个index.js我需要打包到index.html中使用,我们就需要在根目录创建一个webpack的配置文件webpack.config.js

三、编写webpack.config.js

基本的配置如下:

module.exports = {
  mode: 'development',
  entry: {
    main: path.resolve(__dirname, 'src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'  
  }

并且在package.json中配置运行命令(直接yarn build打包):

"build": "webpack --config webpack.config.js"

运行打包命令后,我们会发现根目录下多出dist文件夹,里面的main.js是对index.js的打包,我们将其引入html。

四、编写index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script src="./dist/main.js"></script>  <!-- 引入main.js -->
</body>

</html>

我们跑一下这个html,成功打印!

image.png

五、几个问题

问题一: 我们如果修改html中打印的东西,重新打包,那么处于dist文件夹下的文件依然还是main.js。这就会有一个问题,CDN网络分发的情况下,分布服务器感知总部服务器的变更一般是通过资源文件名的变更而变更的。

所以,该想个法子了!可不可以在每次打包后在文件名后拼接一串哈希值呢?
我们在webpack配置文件中将 filename 改成 'main.[hash:8].js'

再去打包,发现dist中新增了一个文件!成功解决这个问题。

问题二: 如果我们想让main.js自动引入到这个html中来而不需要我们手动引入呢?
可以安装html-webpack-plugin插件解决这个问题。

配置文件代码如下:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: {
    main: path.resolve(__dirname, 'src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename:'main.[hash:8].js'
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'index.html')
    })
  ]
}

我们把之前我们手动在html中引入main.js的代码删除,重新打包,会发现dist文件夹下出现index.html,并且自动引入了main.js,运行html也能得到相应的打印!

问题三: 我们可以瞅一眼,dist文件夹下一坨main.js混杂在一起,那么之前打包过的文件我们是不是可以删除呢?
可以安装clean-webpack-plugin插件来解决。

配置文件继续添加引入并使用:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  mode: 'development',
  entry: {
    main: path.resolve(__dirname, 'src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js'  //'main.[hash:8].js':每次打包的文件名不一样 让分布服务器能感知到主服务器发生变化
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'index.html')
    }),
    new CleanWebpackPlugin(),  //把历史打包文件清除掉
  ]
}

打包完成后,我们去dist文件夹查看,发现瞬间明朗了!

你以为问题结束了?还没有呢!

问题四:CleanWebpackPlugin是怎么把历史的打包文件清除的呢?它怎么知道哪些是历史的包呢?

思路:在把的包放进dist文件夹历史的包清除掉不就可以了吗?
那么这就涉及到执行时间的问题了,我们去webpack官方文档发现webpack内置了一系列的钩子函数(compiler 钩子),分别会在打包过程中的各个时间节点执行。 (🚩ps:compilation 钩子是编译阶段的钩子函数)

再去看看官方文档中对plugin的介绍

插件是webpack的支柱功能,插件目的在于解决loader无法实现的其他事,webpack插件是一个具有apply方法的JavaScript对象。apply方法会被webpack compiler调用,并且在整个编译生命周期都可以访问compiler对象。

好了,到这里,我们基本的铺垫才做好。

六、正题:打造一个简单插件

我们需要打造一款可以自动在main.js后拼接一个时间戳的插件,并且能自动引入到html中。

思路

  1. 拼接时间戳应该在html文件生成出来之前完成
  2. 我们的plugin应该在html-webpack-plugin之前生效

我们在根目录创建stamp-webpack-plugin.js来打造插件

const HtmlWebpackPlugin = require('html-webpack-plugin')

class StampPlugin {
  apply(compiler) {
    //compilation是在编译这件事被创建之后就会执行(可以保证我们的插件一定会在文件生成之前执行)
    //注册一个名为StampWebpackPlugin的方法
    compiler.hooks.compilation.tap('StampWebpackPlugin', (compilation, compilationParams) => {  //tap用来触发钩子函数
      //参数compilation是模块
       HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tap('StampWebpackPlugin', (data, cb) => {  //使用HtmlWebpackPlugin提供的钩子beforeAssetTagGeneration(静态标签生成之前)
        let jsSrc = data.assets.js[0]  //拿到'main.js'
        data.assets.js[0] = `${jsSrc}?${new Date().getTime()}`  //拼接时间戳后替换
      });

    })
  }
}

module.exports = StampPlugin

最后,我们只需要在webpack配置文件引入我们打造的插件就行了:

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const StampPlugin=require('./stamp-webpack-plugin.js')

module.exports = {
  mode: 'development',
  entry: {
    main: path.resolve(__dirname, 'src/index.js')
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'main.js' 
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, 'index.html')
    }),
    new CleanWebpackPlugin(),  //把历史打包文件清除掉
    new StampPlugin()
  ]
}

再次打包,会发现html自动引入main.js,并拼接上了时间戳,再也不用手动在output的文件名中添加了!

这里只打造一个简单的插件,流程并不复杂,看完之后大佬们就可以自己去打造插件了!

全部评论

相关推荐

06-27 12:30
延安大学 C++
实习+外包,这两个公司底层融为一体了,如何评价呢?
一表renzha:之前面了一家外包的大模型,基本上都能答出来,那面试官感觉还没我懂,然后把我挂了,我都还没嫌弃他是外包,他把我挂了……
第一份工作能做外包吗?
点赞 评论 收藏
分享
06-13 10:15
门头沟学院 Java
想去夏威夷的大西瓜在...:我也是27届,但是我现在研一下了啥项目都没有呀咋办,哎,简历不知道咋写
点赞 评论 收藏
分享
避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
家人们,我现在真的好纠结。我是26届的,目前还没有实习过。我现在的情况是,想参加秋招,但是感觉自己的简历特别空,没有实习经历会不会秋招直接凉凉啊?可我又听说现在很多公司对26届实习生也不太感冒,说什么不确定性大。而且我最近在准备考公,时间上也有点冲突。要是把时间花在实习上,备考时间就少了。但要是不实习,又怕以后就业有问题😫有没有懂行的友友帮我分析分析:26届现在不实习,秋招找工作真的会很难吗?考公和实习该怎么平衡啊?如果现在不实习,考完公再去找实习还来得及吗?真的太焦虑了,希望大家能给我点建议🙏
小破站_程序员YT:我可能和大家的观点不一样。人的精力是有限的,不能既要还要。你又想实习又想考公最后又要秋招上岸,我觉得哪有那么多的选择。你如果想考上岸,那就全力以赴。如果想秋招上岸,就继续投实习,投没了,就继续准备秋招,秋招不行继续春招。别到最后,考公没上岸,觉得是花了时间浪费在找实习上了, 秋招没上岸,觉得是浪费时间准备考公去了。我是认为很难说可以去平衡 不喜勿喷,可以叫我删除
实习与准备秋招该如何平衡
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务