1 Basic Review

Let’s start with a review of common WebPack configurations, which we’ll use later.

1.1 Common WebPack Configurations

// Entry file entry: {app:'./src/js/index.js'}, // output: {filename:'[name].bundle.js',
    path: path.resolve(__dirname, 'dist'),
    publicPath: '/'// Make sure file resources are properly accessed at http://localhost:3000}, // developer toolssource-map
  devtool: 'inline-source-map'// Create devServer: {contentBase:'./dist',
    hot: trueNew CleanWebpackPlugin(['dist'// new HtmlWebpackPlugin({title:'Output Management'}), / / in order to more easily view to repair (patch) rely on new webpack. NamedModulesPlugin (), / / hot update module new webpack. HotModuleReplacementPlugin ()], / / environment mode:"development"// loader configuration module: {rules: [{test: /\.css$/,
        use: [
          'style-loader'.'css-loader'] {},test: /\.(png|svg|jpg|gif)$/,
        use: [
          'file-loader']]}}Copy the code

Here we will focus on module and plugins properties, because today’s focus is on loader and plugin, and these two properties need to be configured.

1.2 Packaging Principles

  • Identification entry file
  • Identify module dependencies layer by layer. Commonjs, AMD, or ES6 imports are analyzed by WebPack. To get code dependencies)
  • What WebPack does is analyze the code. Transform code, compile code, output code
  • The result is packaged code

These are some of the basics of WebPack and are very helpful in understanding how WebPack works.

2 loader

OK, the first hero of the day

2.1 What Is Loader?

Loader is a file loader that loads resource files, performs some processing, such as compilation and compression, on these files, and finally packages them into a specified file

  • Multiple Loaders can be used to process a file. The execution sequence of loaders is reversed, that is, the last loader is executed first and the first loader is executed last.
  • The first loader that executes receives the contents of the source file as a parameter, and the other Loaders receive the return value of the previous loader that executes as a parameter. The last loader to execute returns the JavaScript source code for this module

2.2 Write a Loader by hand

Requirements:

  1. Processing. TXT files
  2. Invert the string
  3. Uppercase

For example, abcdefg is converted to Gfedcba

OK, here we go

1) Create two loaders (the local loader is used as an example)

Why create two LaoDers? The reasons will be explained later

reverse-loader.js

module.exports = function (src) {
  if (src) {
    console.log('--- reverse-loader input:', src)
    src = src.split(' ').reverse().join(' ')
    console.log('--- reverse-loader output:', src)
  }
  return src;
}
Copy the code

uppercase-loader.js

module.exports = function (src) {
  if (src) {
    console.log('--- uppercase-loader input:', src)
    src = src.charAt(0).toUpperCase() + src.slice(1)
    console.log('--- uppercase-loader output:'SRC)} // Why? Since it would be a syntax error to return the converted string, // write import to convert it to a usable stringreturn `module.exports = '${src}'`}Copy the code

The loader structure is very simple. It accepts a parameter and returns a content.

Then create a TXT file

2) mytest. TXT

abcdefg
Copy the code

3) Now configure WebPack

module.exports = {
  entry: {
    index: './src/js/index.js'}, plugins: [...] , optimization: {... }, output: {... }, module: { rules: [ ..., {test: /\.txt$/,
        use: [
          './loader/uppercase-loader.js'.'./loader/reverse-loader.js'}]}}Copy the code

This completes the configuration

4) We import the script in the entry file

Why do we need to import here? Didn’t we configure Webapck to handle all of our.txt files?

Because WebPack does filtering, webpack will not package the file if it is not referenced, and your loader will not execute it

import _ from 'lodash';
import txt from '.. /txt/mytest.txt'
import '.. /css/style.css'
function component() {
  var element = document.createElement('div');
  var button = document.createElement('button');
  var br = document.createElement('br');

  button.innerHTML = 'Click me and look at the console! ';
  element.innerHTML = _.join('【' + txt + '】');
  element.className = 'hello'
  element.appendChild(br);
  element.appendChild(button);

  // Note that because a network request is involved, some indication
  // of loading would need to be shown in a production-level site/app.
  button.onclick = e => import(/* webpackChunkName: "print"* /'./print').then(module => {
    var print = module.default;

    print(a); });return element;
}
document.body.appendChild(component());
Copy the code

Package. The json configuration

{... ."scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"."build": "webpack --config webpack.prod.js"."start": "webpack-dev-server --open --config webpack.dev.js"."server": "node server.js"},... }Copy the code

And then execute the command

npm run build
Copy the code

So our loader is done.

Now answer why write two loaders?

See the order of execution? Our configuration looks like this

use: [
  './loader/uppercase-loader.js'.'./loader/reverse-loader.js'
]
Copy the code

As mentioned above, multiple Loaders can be used to process a file, and the order of execution of loaders is reversed

We can also write loader to parse custom templates, such as vue-loader is very complex, it will write a large number of. Vue file parsing, and then generate the corresponding HTML, JS and CSS.

We only describe the basic usage here. If you need more, please check the Loader official documentation.

3 plugin

3.1 What is Plugin?

A number of events are broadcast during the life cycle of a Webpack run, and the Plugin can listen for these events and change the output when appropriate through the API provided by Webpack.

What is the difference between plugin and loader?

For loader, it is A converter to compile file A into file B. For example, a.css or A.less is converted to B. CSS

Plugin is an extender, which enrichis Wepack itself. It is aimed at the whole process of Webpack packaging after loader ends. It does not operate files directly, but works based on the event mechanism, and will listen to some nodes in the process of Webpack packaging to perform a wide range of tasks.

3.2 A minimal plug-in

/plugins/ myplugin.js (local plugin)

Class MyPlugin {// constructor (options) {console.log()'MyPlugin constructor:'} // Apply the function apply (compiler) {// Bind the hook event compiler.plugin()'compilation', compilation => {
      console.log('MyPlugin')
    ))
  }
}

module.exports = MyPlugin
Copy the code

Webpack configuration

const MyPlugin = require('./plugins/MyPlugin')
module.exports = {
  entry: {
    index: './src/js/index.js'
  },
  plugins: [
    ...,
    new MyPlugin({param: 'xxx'})],... };Copy the code

This is the simplest plugin (although we didn’t do anything)

  • After webpack is started, a new MyPlugin(options) is executed to initialize a MyPlugin instance during the configuration reading process.
  • After initializing the Compiler object, myPlugin.apply(Compiler) is called to pass the compiler object to the plug-in instance.
  • Once the compiler object is acquired, the plug-in instance can listen for events broadcast by Webpack through compiler.plugin(event name, callback function).
  • The Compiler object can also be used to manipulate webpack.

What is compiler? Compilation?

  • The Compiler object contains all the configuration information of the Webpack environment, including options, loaders and plugins. This object is instantiated when Webpack starts. It is globally unique and can be simply understood as an instance of Webpack.

  • The Compilation object contains the current module resources, compile-generated resources, changing files, and so on. When Webpack is running in development mode, a new Compilation is created each time a file change is detected. The Compilation object also provides many event callbacks for plug-ins to extend. Compiler objects can also be read from the Compilation.

The difference between Compiler and Compilation is that:

Compiler represents the entire Webpack lifecycle from startup to shutdown, while Compilation simply represents a new Compilation.

3.3 event flow

  • Webpack organizes this complex production line through Tapable.
  • Webpack’s event flow mechanism ensures the orderliness of plug-ins and makes the whole system very extensible.
  • Webpack’s event flow mechanism applies the observer pattern, much like EventEmitter in Node.js.

The binding event

compiler.plugin('event-name', params => {
  ...	  
});
Copy the code

Triggering event

compiler.apply('event-name',params)
Copy the code

3.4 Points needing attention

  • As long as the Compiler or Compilation object is available, new events can be broadcast, so a newly developed plug-in can broadcast events for other plug-ins to listen on.
  • The Compiler and Compilation object passed to each plug-in is the same reference. This means that changing the properties of the Compiler or Compilation object in one plug-in can affect subsequent plug-ins.
  • Some events are asynchronous, and these asynchronous events take two parameters. The second parameter is a callback function that needs to be called to notify WebPack when the plug-in has finished processing the task before moving on to the next process. Such as:
compiler.plugin('emit'.function(compilation, callback) { ... // If no callback is executed, the running process will remain stuck executing callback() below; });Copy the code

With respect to complier and compilation, WebPack defines a large number of hook events. Developers can customize the processing anywhere they want.

Compiler Hook Documentation

Compilation Hook Documentation

3.5 Write a Plugin by hand

Scene:

The small program MPvue project, compiled by Webpack, generates subpackages (which we introduced as subpackages into the main program) and then checks into the main package. After the subpackage is generated, the public static resource WXSS reference address needs to be added to the subPages/enjoy_given prefix.

Before the plug-in was written, the generated resources were such that this path could not be accessed properly if introduced as a subcontract to the main package.

So here comes the demand:

Dist /static/ CSS /pages directory, all pages style files (WXSS files) into the path of public resources.

Because all page styles refer to the generic style vender.wxss

@import "/static/ CSS /vendor. WXSS "; To: @ import "/ subPages/enjoy_given/static/CSS/vendor. WXSS";Copy the code

“OK” to start!

1) Create the plug-in file csspathtransfor.js

CssPathTransfor.js

class CssPathTransfor {
  apply (compiler) {
    compiler.plugin('emit', (compilation, callback) => {
      console.log('--CssPathTransfor emit') // Traverses all resource filesfor (var filePathName inCompilation. assets) {// Check whether the corresponding files are in the specified directoryif(/static\/ CSS \/pages/i.test(filePathName)) {// Introduces the path regular const reg = /\/static\/ CSS \/vendor\.wxss/ I // Needs to replace the final string const finalStr ='/subPages/enjoy_given/static/css/vendor.wxss'// Get the file contentslet content = compilation.assets[filePathName].source() || ' 'Content = content.replace(reg, finalStr) // Rewrite the specified output module programmer. Assets [filePathName] = {source () {
              return content;
            },
            size () {
              return content.length;
            }
          }
        }
      }
      callback()
    })
  }
}
module.exports = CssPathTransfor
Copy the code

It looks like a lot, but it’s actually going through the Compilation. Assets module. Regular replacement is performed for files that meet the requirements.

2) Modify the WebPack configuration

var baseWebpackConfig = require('./webpack.base.conf')
var CssPathTransfor = require('.. /plugins/CssPathTransfor.js') var webpackConfig = merge(baseWebpackConfig, { module: {... }, devtool: config.build.productionSourceMap ?'#source-map' : false, output: {... }, plugins: [..., // new CssPathTransfor(),]})Copy the code

After the plug-in is written, execute the compile command

Do ~

For more information, see how to Write a Plugin.