This is the 6th day of my participation in the August More Text Challenge

Usually we don’t play with the WebPack configuration during development, it is the big guy to us, we just write the business code, for many commonly used loader and plugin roughly know what it is, but actually do what is like a layer of fog.

So I’ve written this article in the hope that you’ll be able to clear up the fog and understand the functions of common Loaders and plugins.

Commonly used loader

Webpack’s loader is used to process individual files. Alternatively, it applies multiple Loaders to a matching file in order to return a string of JS content, allowing webPack to be modularized. The key points are:

  • The loader returns a string of JS contents.

  • Loader is a converter that processes source files.

  • In the configuration, multiple loaders are executed in sequence from back to front.

babel-loader

Babel-loader is a standard part of Webpack build projects because it implements a core compatibility function: converting the new ES syntax into ES5 syntax that runs on most browsers.

{
  module: {
    rules: [{test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',}},// ...]}}Copy the code

Because of the complexity of Babel configuration, we usually don’t configure it on WebPack and use a babel-specific configuration file instead. reference

  • babel.config.js. Global configuration (project level, under execution directory)
  • .babelrc. The local configuration (directory level) is merged with the project level babel.config.js. If the current directory does not have.babelrc, go up to the nearest one. If the file is outside the project root directory,.babelrc in the same directory as the file is not applied.

In addition, babel.config.js is a JS file that can be imported into modules; Babelrc is a JSON file.

Babel’s configuration files often need to be preset, which is a packaging of common Babel transformations. I’m not going to do that here

css-loader

Css-loader compiles the CSS file into an object and records the necessary information. This object cannot be used directly, and needs to be used with style-loader to implement style mounting.

// index.css
.red {
  background-color: #f04;
}
Copy the code

The above style will be converted to an object that looks like this.

An important function of CSS-Loader is to support the implementation of CSS-Module, which is a popular solution for componentization development of CSS. The configuration is as follows.

options: {
  modules: {
    localIdentName: '[name]__[local]__[hash:base64:5]',}},Copy the code

style-loader

Style-loader processes the object returned by csS-loader, puts the CSS content in the style tag, and then in the DOM tree (default is , you can use options.insert to change the mount position). Notice that instead of generating a CSS file, the contents of the CSS file are saved as strings in the script.

In a real production environment, we still need to extract CSS files. We changed to use MiniCssExtractPlugin. Loader.

MiniCssExtractPlugin.loader

The mini-CSS-extract-plugin is used to extract CSS content into a separate file. The default is to pack all CSS content into one CSS file. The Mini-CSS-extract-Plugin is itself a plug-in, but it also provides a loader of its own. You must use the corresponding Plugin when using loader; otherwise, an error message is displayed.

In general we will according to build environment, is the use of style – loader or MiniCssExtractPlugin. Loader:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (env) = > ({
  module: {
    rules: [{test: /\.css$/,
        use: [
          env.production ? MiniCssExtractPlugin.loader : 'style-loader'.'css-loader'.// ...]]}},// ...
  plugins: [
    new MiniCssExtractPlugin(),
  ]
})
Copy the code

If you use the HTML-webpack-plugin, it will recognize the CSS file name generated by the Mini-CSS-extract-plugin and embed it in the generated HTML as a link. HTML – webpack – said the plugin:

If you have any CSS assets in webpack’s output (for example, CSS extracted with the mini-css-extract-plugin) then these will be included with <link> tags in the HTML head.

postcss-loader

Postcss-loader is a tool for handling styles and supports a variety of useful plug-ins. We usually use a separate postcss.config.js configuration (you can also configure it directly on the WebPack configuration).

Its power lies in its ability to use many useful plug-ins, such as:

  • autoprefixer: Address browser compatibility issues by adding browser-specific prefixes to selectors or style rules. Such as::placeholder {}Will convert to various browser-specific selectors, there::-webkit-input-placeholder {} input::-ms-input-placeholder {}And so on. Also liketransformProperties. Autoprefixer is almost a standard plug-in for PostCSS because it handles CSS compatibility issues.
  • Postcss-pxtorem: Convert CSS pxto REM units. This is needed to develop H5 pages based on REM adaptation.

Less – loader/sass – loader, etc

We usually don’t write CSS directly. Instead, we use preprocessors like less and Sass, mainly using the selectors nested syntax that CSS doesn’t have, which greatly improves our style writing efficiency. CSS preprocessors are standard on almost every project.

Depending on the project, we will choose to use different CSS preprocessors, for which we need to install different preprocessor Loaders.

If we use less-loader, we need to install less as well as less-loader, otherwise we will get an error when importing less files. The same goes for other preprocessor loaders. The configuration looks something like this

{
  test: /\.less$/,
  use: [
    env.production ? MiniCssExtractPlugin.loader : 'style-loader'.'css-loader'.'postcss-loader'.'less-loader']},Copy the code

Note that less-loader must be placed after postCSs-loader, because loader is executed from right to left. Postcss-loader cannot handle the syntax of less, such as //, After less-Loader is converted to the CSS, postCSS-Loader can understand and process the CSS.

file-loader

File-loader is used to hash resources imported from JS files into the build directory (by default). The script can then take the new resource name and place it where it needs to be, such as img.url. The configuration is written like this:

{
  test: /\.(png|jpe? g|gif)$/,
  use: 'file-loader'
}
Copy the code

After WebPack 5, however, the loader is built in (no additional file-loader installation is required) and the concept is changed: Asset Module. In WebPack 5, we could write:

{
  test: /\.(png|jpe? g|gif)$/,
  type: 'asset/resource'
}
Copy the code

url-loader

Url-loader converts imported resources to base64 URIs. The original resource is not copied to the build directory, it becomes a very long string encoding. Base64 converts three bytes to four bytes, resulting in large resources, especially for large files. For small resource consumption is low, but can save one HTTP request. Base64 is generally used to optimize network requests and reduce the number of small resource requests.

So we usually give a threshold (usually 8194 bytes, which is about 8K). If the file size is smaller than the specified size, use base64 (url-loader). Otherwise, copy resources (file-loader).

{
  test: /\.(png|jpe? g|gif)$/,
  use: [
    {
      loader: 'url-loader'.options: {
        limit: 8194.// In bytes}}// You don't need to write file-loader here, but you need to install it.
    // Cannot find module 'file-loader' Cannot find module 'file-loader']}Copy the code

If the resource is larger than or equal to 8194 bytes, url-loader will automatically find file-loader to process (you can use options.fallback to specify which loader to use if the condition is not met).

Also, WebPack 5 has a built-in loader called Asset/Inline. Written as type: asset/inline or type: ‘asset’, Parser: {dataUrlCondition: {maxSize: 8 * 1024}}. The latter is written with a threshold.

raw-loader

Raw-loader extracts the content of the file and converts it to a string. It is used to extract text files, such as TXT and JSON. Webpack 5 has it built in, written as type: ‘asset/source’.

I tried to extract the contents of the binary file and got a bunch of garbled characters.

Common plugin

Plugin can handle some of the lifecycle hook functions of WebPack and change the output by calling the API provided by WebPack when appropriate.

By using the Plugin, we are able to enhance webPack functionality and solve the various problems that the Loader cannot handle during the WebPack packaging process.

html-webpack-plugin

Html-webpack-plugin is a plugin that simplifies the process of putting packaged files into HTML, because the packaged files will generate multiple files, may have hash values, may unpack, if you have to import all of them into HTML files one by one, it will be very tedious and easy to write wrong. This plugin will help simplify this aspect of our work.

clean-webpack-plugin

The clean-webpack-plugin is used to clear the build directory (the directory pointed to by the output.path configuration) before building. This prevents residual redundant files. For example, after modifying the source file, the hash value of the packaged new file changes, and the old file that uses the old hash is retained.

I see a honey way to implement the clean-webpack-plugin. Add the execute script to package.json

"scripts": {
  "prebuild": "rm -rf dist/*".// ...
}
Copy the code

In this case, the prebuild script is executed before the build script is executed to clear the build directory. In a sense, it can. But if the output directory is changed later, it is easy to miss this change.

copy-webpack-plugin

The copy-webpack-plugin can copy multiple files or folders into a build directory (that is, the directory to package the output of files). Usage Scenarios:

  • Copy the static folder and put some resources imported without import. For example, there are some relatively niche third-party libraries that do not provide ES modularity files, and some SDKS. Using the plugin, we can write in the template HTML file<script src="/public/lib-a.js"></script>
  • Copy of the robot.txt file.
new CopyWebpackPlugin([
  {
    from: path.join(__dirname, 'static'), 
    to: 'static'.ignore: ['*'] {},from: resolvePath('robots.txt'),
    to: 'robots.txt'}]Copy the code

webpack.ProvidePlugin

ProvidePlugin is a plug-in built into WebPack. The function is to automatically load modules without writing a line of import or require every time, suitable for some basic modules that are often imported to other modules. Note that this plugin does not inject the specified module into the global scope, but allows you to save a line of import logic in the module file. Such as:

plugins: [
  new webpack.ProvidePlugin({
    $: 'jquery'._map: ['lodash'.'map'"})"Copy the code

webpack.DefinePlugin

Webpack.defineplugin is a built-in Webpack plug-in that replaces a specified variable with another value at compile time. It’s kind of like a macro in C.

If a scope has a variable with the same name, the variables defined in DefinePlugin will not override it. You can think of it as a scope higher than the global scope, although they are not actually injected into the scope.

In essence, replace the string in the form of the matched variable in the JS file with the specified string.

new webpack.DefinePlugin({
  PRODUCTION: JSON.stringify(!! env.production),CONSOLE: 'console.log(" I'll just output it ")'
})
Copy the code
/ / the source code
console.log(PRODUCTION)
CONSOLE

// After production uses DefinePlugin, convert to:
console.log(true)
console.log("I'm just going to print it.")
Copy the code

terser-webpack-plugin / uglifyjs-webpack-plugin

Uglifyjs-webpack-plugin and Terser-webpack-plugin are both code compression plugins. The former is deprecated and the latter is recommended.

When we compressed the code, we used Ugliliy-es (ugliliy-JS does not support ES6, ugliliy-es is its Harmony branch, which supports ES6+), but ugliliy-es is no longer maintained. So someone forked uglip-es, created Terser, and maintained it continuously.

Webpack itself comes with a code compression plug-in, originally using Uglip-ES, which was changed to Terser after V4.26.0. Code compression plugins will only be executed in a production environment, although you can optionally disable code compression by setting optimization.minimize to false.

Of course, you can use the latest version of Terser or do some configuration and install a separate Terser-webpack-plugin. Unlike normal plug-ins, the code compression plug-in configuration needs to be placed in the optimization.minimizer location.

const TerserPlugin = require('terser-webpack-plugin')

optimization: {
  minimizer: [
    new TerserPlugin({
      parallel: true./ / parallel
      terserOptions: {
        compress: {
          drop_console: false // Drop console to reduce memory leaks}}}),]}Copy the code

At the end

These are common loaders and plugins. They are used in almost every project and it is necessary to take time to understand them.

Practice is the sole criterion for testing truth. If you want to get a better understanding of these loaders and plugins, I recommend doing the WebPack configuration yourself from zero to one and seeing the output from the different configurations.

reference

  • Why does webpack4 support compression of ES6 syntax by default?
  • Uglifyjs-webpack-plugin switches to terser-webpack-plugin history