/ What does this plugin do? /

The WLB-WebPack-Plugin automatically injects “anti-inwrapping and anti-code addiction logic” into webpack packages during off-day and off-day hours, making it the perfect choice for front-end engineers looking for work-life-balance. (Manual funny)

Project address (welcome to star) : github.com/shadowings-…

Before preventing addiction:

After anti-addiction:

When using Webpack, you get the following prompts:

How does this plugin work? /

To implement the WLB-WebPack-plugin, we first need to know what the plugin does. When I conceived the plugin, I listed the following four features:

1. It needs to be a WebPack plug-in — it needs to follow the WebPack plug-in specification.

2. It must be able to determine working hours and non-working hours and support user configuration.

3. It must be able to inject “specific logic” into the package during non-working hours.

4, “specific logic” includes: if the node terminal, directly print “anti-addiction slogan”; If you use the Web terminal, display the anti-addiction slogan on the page.

Then we can have fun writing code for these four function points

2-1. Write a WebPack plugin first

Webpack example in the website has written very understand, can directly see the: www.webpackjs.com/contribute/…

To recap, a WebPack plug-in consists of:

1. A JavaScript naming function. (In our plugin, we use class instead of function, which is actually the same thing.)

2. Define an Apply method on the prototype of the plug-in function.

3. Specify an event hook bound to WebPack itself.

4. Handle specific data for webPack internal instances.

5. Call the webPack callback when the functionality is complete.

The general structure of our WLB-Webpack-plugin looks like this:

Class WLBPlugin {constructor(options) {// Handle the logic for initialization parameters} apply(compiler) {// handle the logic to determine whether it is working time Compiler.hooks. Emit. Tap ('WLBPlugin', (compilation) => {})}} Module.exports = WLBPlugin;Copy the code

2-2. Process user configuration

Before dealing with user configuration, we need to define what configuration can be passed by users. When I was thinking about the plug-in, I defined the following configuration items:

  • StartWorkingTime Start time

  • EndWorkingTime Time when work ends

  • IgnoreWeekend Indicates whether to ignore weekends

  • WarningMessage Indicates a non-working time message

  • ReplaceOriginBundle Whether to replace the originally generated bundle

Special mention is made to the replaceOriginBundle configuration item, which is used to decide whether to incrementally add anti-addiction code or simply replace the bundle content with anti-addiction code. In most cases, though, a straightforward substitution of the code would suffice. However, if you use some custom scaffolding, replacing the code directly will cause the whole project to fail, so incremental additions will work in this case.

After defining the configurations, we need to initialize them and store them in the WLBPlugin class. The object. assign function is a good fit here.

Const DEFAULT_WARNING_MESSAGE = 'Drop the volume! It's not working time! In order to create a good working environment, the WLB plugin has injected "anti-introdution & anti-addiction logic" into the package. '; const DEFAULT_OPTIONS = { startWorkingTime: 10, endWorkingTime: 20, ignoreWeekend: false, warningMessage: DEFAULT_WARNING_MESSAGE, replaceOriginBundle: true, }; class WLBPlugin { constructor(options) { this.options = Object.assign(DEFAULT_OPTIONS, options || {}); } apply(compiler) {// Process the logic to determine whether it is working time in compiler.hooks. Emit. Tap ('WLBPlugin', (compilation) => {// Handle the logic to inject "anti-codec & anti-codec" into the package})}}Copy the code

2-3. Determine whether it is working time

When we can read the configuration item using this.options, we can use the built-in Date object to get the current time and week, and compare it with the configuration item, like the following code:

const date = new Date(); const day = date.getDay(); const hour = date.getHours(); const isWorkdays = day <= 4 || ignoreWeekend; const isWorkOvertime = ! isWorkdays || hour < startWorkingTime || hour >= endWorkingTime; If (isWorkOvertime) {// Handle non-workovertime logic}Copy the code

2-4. Generate and inject “Anti-inwrapping & Anti-Addiction Code”

The last and most critical step is to generate and inject code, starting with “Generate code.”

2-4-1. Generate code

From the beginning, the generated code needs to:

1. In Node, print the “Anti-addiction slogan” directly.

2. On the Web side, you need to display “anti-addiction slogan” on the page.

The Node side is relatively easy, just go to console.log. But on the Web side, we need to do this by manipulating the DOM.

In the code below, a timer is started on the Web side, and every second the content in the tag is replaced with “anti-addiction slogan”, and only one timer is started by checking window.showwlbplugininfo.

const htmlTemplate = (slogan) => { return `<div><h1>${slogan}</h1><a Href = \ \ "https://github.com/shadowings-zy/wlb-webpack-plugin\" > by "WLB - webpack - the plugin code within the volume & anti-addiction webpack plug-in" support < / a > < / div > `; }; const generateCode = () => { const slogan = getRandomSlogan(); return ` ; (function() { const introduction = '${slogan.introduction}'; const content = '${slogan.content}'; console.log(introduction + content); if (typeof window! =='undefined' && ! window.showWLBPluginInfo) { window.setInterval(function() { document.body.innerHTML="${htmlTemplate(slogan.content)}"; }, 1000) window.showWLBPluginInfo=true } })() `; };Copy the code

2-4-2, inject code

To inject code, you need to use the hooks provided by WebPack to iterate over and read its build artifacts, then generate code, and finally inject, as shown in the following code:

class WLBPlugin { // ... apply(compiler) { // ... if (isWorkOvertime) { console.log(chalk.red(warningMessage)); compiler.hooks.emit.tap('WLBPlugin', Object. Keys (compilation. Assets). ForEach ((item) => {let content = compilation.assets[item].source(); if (this.options.replaceOriginBundle) { content = generateCode(); } else { content = content + generateCode(); } // Update the compilation. Assets [item] = {source: () => content, size: () => content.length,}; }); }); }}})Copy the code

2-5. Overall code display

For modularized code, see the code in the repository:

Github.com/shadowings-…

The following code is for demonstration only:

const chalk = require('chalk'); Const WORK_LIFE_BALANCE_SLOGAN_LIST = [{introduction: '[work-life-balance-webpack-plugin], content: [work-life-balance-webpack-plugin] [work-life-balance-webpack-plugin] [work-life-balance-webpack-plugin] [work-life-balance-webpack-plugin] [work-life-balance-webpack-plugin] [work-life-balance-webpack-plugin] 'Moderate code is good for brain, excessive code is bad for body, arrange your time properly and enjoy a healthy life ',},]; Const DEFAULT_WARNING_MESSAGE = 'Drop the volume! It's not working time! In order to create a good working environment, the WLB plugin has injected "anti-introdution & anti-addiction logic" into the package. '; const DEFAULT_OPTIONS = { startWorkingTime: 10, endWorkingTime: 20, ignoreWeekend: false, warningMessage: DEFAULT_WARNING_MESSAGE, replaceOriginBundle: true, }; const getRandomSlogan = () => { const index = Math.floor( Math.random() * WORK_LIFE_BALANCE_SLOGAN_LIST.length, ); return WORK_LIFE_BALANCE_SLOGAN_LIST[index]; }; const htmlTemplate = (slogan) => { return `<div><h1>${slogan}</h1><a Href = \ \ "https://github.com/shadowings-zy/wlb-webpack-plugin\" > by "WLB - webpack - the plugin code within the volume & anti-addiction webpack plug-in" support < / a > < / div > `; }; const generateCode = () => { const slogan = getRandomSlogan(); return ` ; (function() { const introduction = '${slogan.introduction}'; const content = '${slogan.content}'; console.log(introduction + content); if (typeof window! =='undefined' && ! window.showWLBPluginInfo) { document.body.setAttribute('style', 'display:flex; flex-direction:column; width:100vw; height:100vh; padding:0; margin:0; justify-content:center; text-align:center; ') window.setInterval(function() { document.body.innerHTML="${htmlTemplate(slogan.content)}"; }, 1000) window.showWLBPluginInfo=true } })() `; }; class WLBPlugin { constructor(options) { this.options = Object.assign(DEFAULT_OPTIONS, options || {}); } apply(compiler) { const { startWorkingTime, endWorkingTime, ignoreWeekend, warningMessage, replaceOriginBundle, } = this.options; const date = new Date(); const day = date.getDay(); const hour = date.getHours(); const isWorkdays = day <= 4 || ignoreWeekend; const isWorkOvertime = ! isWorkdays || hour < startWorkingTime || hour >= endWorkingTime; if (isWorkOvertime) { console.log(chalk.red(warningMessage)); compiler.hooks.emit.tap('WLBPlugin', Object. Keys (compilation. Assets). ForEach ((item) => {let content = compilation.assets[item].source(); if (replaceOriginBundle) { content = generateCode(); } else { content = content + generateCode(); } // Update the compilation. Assets [item] = {source: () => content, size: () => content.length,}; }); }); } } } module.exports = WLBPlugin;Copy the code

So, our plug-in development is complete!