webpack is a module bundler for JavaScript. Front-end applications contain many types of assets such as JavaScript, (HOPEFULLY) Typescript, JSON, HTML, CSS, and images. webpack (after you've configure it to process files in a certain manner) will generate static assets, representing your applications modules so that they can be interpreted by a browser.
A "hook" in software development is a place in code that allows you to tap into a module to either provide different behavior or to react when something happens. webpack provides the following types of hooks:
For an example scenario, let's pretend we want to make sure that, when we build our application, no file is outputted that contains the string
MY_SUPER_SECRET
. Perhaps we want to do this to provide a last line of defense from a developer including a sensitive value in our code and we want to prevent webpack from even compiling it. If that string is detected, we'd like webpack to:
throw an error.
not emit any files at any point during the build.
To do this, let's look at the
shouldEmit
compiler hook. This hook is called
before
assets are emitted and will allow us to error out and not emit assets if our validation fails.
To start, let's create a new plugin class and add it to the
plugins
block of our
webpack.config
:
Note that, while I've defined my plugin in a separate class/file, you could include it in your webpack.config inline.
Now, let's take a look at the plugin:
// src/plugins/asset-validator-plugin.tsimport*aswebpackfrom'webpack';exportclassAssetValidatorPlugin{apply(compiler:webpack.Compiler){compiler.hooks.shouldEmit.tap('AssetValidatorPlugin',(compilation:webpack.compilation.Compilation)=>{this.validateAssets(compilation);publicvalidateAssets(compilation:webpack.compilation.Compilation){constassets=Object.entries(compilation.assets);constregex=newRegExp('MY_SUPER_SECRET','g');// Loop through each asset and check to see if it contains any sensitive stringsfor(leti=0;i<assets.length;i++){const[fileName]=assets[i];constasset=compilation.getAsset(fileName);constsource=asset.source.source();constcontents=convertSourceToString(source);constmatches=contents.match(regex);if(matches){thrownewError("Our tool has identified the presence of the string 'MY_SUPER_SECRET' in your compiled code. Compilation has been aborted."returntrue;// This function is only needed because asset.source.source() can be a string or ArrayBufferconstconvertSourceToString=(source:string|ArrayBuffer):string=>{if(typeofsource==='string'){returnsource;}else{returnnewTextDecoder().decode(source);Enter fullscreen modeExit fullscreen mode
So, let's review what is included our plugin. We've defined our plugin class and, within, are able to tap into the compiler.hooks.shouldEmit hook. In the hook callback, we simply call a validateAssets() function we've defined which loops through all assets that are part of the compilation and use regular expression matching to see if the string exists. We throw an error if it does, short-circuiting the compilation and not emitting any files. If it doesn't contain our special string, we'll return true, compilation will continue, emitting the packaged files as expected.
If you have a need to pass any parameters to your plugin, that can easily be accomplished by defining a constructor in your plugin class like this:
constructor(options:MyPluginOptions){this.options=options;Enter fullscreen modeExit fullscreen mode
Tricking Dependabot into allowing multiple update configs for one package ecosystem
#dependabot#javascript#github
How to inspect transient DOM elements
#javascript#frontend
Built on Forem — the open source software that powers DEV and other inclusive communities.