The preface

This morning, I wrote a simple version of Webpack-flow. I wanted to record it and share it with you. So next, let’s take a look at the webpack-flow process and code implementation part

1. Webpack execution process

  1. The above WebPack implementation process is roughly divided into these steps, and our implementation process is also based on the general direction, we will start from the entry to the method

2. Execute entry and use function

  • Webpack function: We export the function that collects parameters and instantiates the compiler, which is also the execution entry
  • Compiler class: Used to start compiling, exposes a method run that is called to formally start the compilation process
  • ResolveLoader: execute loader to parse es6 syntax. Here we simulate babel-loader to parse ES6 syntax
  • Compose function: implements bottom-up execution of the loader

3. Specific code implementation

3.1 First of all, let’s start from the entrance to see what the entrance does ??????

// Webpack compiler entry
function webpack(options) {
  // 1 -- Parameter merge, merge options passed by webpack call with options in shell
  const argv = process.argv.slice(2)
  const shellOptions = argv.reduce((shellOptions, curr) = > {
    const {key, value} = curr.split('=')
    shellOptions[key.slice(2)] = value
    return shellOptions
  }, {})
  constmergeOptions = {... options, ... shellOptions}// 2 -- Start compiling to get the Compiler object
  const compiler = new Compiler(mergeOptions)
  // 2 -- loads all configured plug-ins
  if (mergeOptions.plugins && Array.isArray(mergeOptions.plugins)) {
    mergeOptions.plugins.forEach(plugin= > plugin.apply(compiler))
  }
  return compiler
}
Copy the code
  • From the above code we can see that the Webpack entry function is no more than the following two functions?
  • Combine the webpack.config parameter with the parameters in the shell command
  • Instantiate the Compiler class to get the instance
  • Loading plugins, which are expected to say that loading is more than subscribing, shows the custom plugin code below
class DonPlugin {
  apply(compiler) {
    // The tap function is used to publish and subscribe via the tapable library
    compiler.hooks.done.tap('done'.() = > {
      console.log('Execution completed.............. ')}}}module.exports = DonPlugin
Copy the code

3.2 Compiler implementation

class Compiler {
  constructor(options) {
    this.hooks = {
      run: new SyncHook(),
      done: new SyncHook()
    }
    this.options = options
  }

  // Start compiling entry
  run() {
    const chunks = {}

    // 2 -- Start determining the entry for compilation
    const {context = process.cwd(), entry} = this.options
    if (typeof entry === 'string') {
      this.options.entry = {main: entry}
    }

    // -- call the hook here
    this.hooks.run.call('run')
    // 3 -- Start traversal loader starts parsing files
    resolveLoader(chunks, this)

    this.hooks.done.call('done')
    // 5 -- Writes files
    const {path: dirPath, filename} = this.options.output
    if(! fs.existsSync(dirPath)) { fs.mkdirSync(dirPath) }Object.keys(chunks).forEach(fileName= > {
      const newPath = path.join(dirPath, `${fileName}.js`)
      chunks[fileName].forEach(content= > {
        fs.writeFileSync(newPath, content, {encoding: 'utf-8'})})})}}Copy the code
  • We’ll start with the constructor, which instantiates the two publish subscribe hooks, Run and done, via tapable. The plugin is executed by subscribing first, and the events triggered are described below.
  • Start by determining the build entry, which in turn resolves dependencies
  • At this point we’ll see the codethis.hooks.run.call('run')This is the time to trigger, in fact our plugin is called at runtime
  • The compiled class will parse the files one by one through the Loader along the entry, which is this coderesolveLoader('done')This code will be explained in the next step
  • This is where the code runsthis.hooks.done.call('done')Loader parsing is complete, and the file will be written soon. So we call the done hook.

At this point, we are reminded of the sentence in the screenshot above, “Webpack will broadcast a specific event at a specific time, and the plugin will execute a specific logic after listening for the event of interest. “The so-called specific time here is different stages to trigger the subscription, and the execution of a specific event is the hook function of the subscription in the plug-in

3.3 Implementation of resolveLoader

function resolveLoader(chunks, compiler) {
  // Import file and loader module
  const {entry, module = {}} = compiler.options
  // Parse the rule
  const {rules} = module
  // Whether to configure loader
  if (rules && Array.isArray(rules)) {
    Object.keys(entry).forEach(keyName= > {
      const modules = []
      // File path
      const filePath = entry[keyName]
      // Read the contents of the file
      const fileContent = fs.readFileSync(filePath, 'utf-8')
      rules.forEach(rule= > {
        // If the loader.test matching rule is met, invoke the corresponding loader to resolve the problem
        if (rule.test.test(filePath)) {
          const methods = rule.use.map(methodPath= > require(methodPath))
          modules.push(compose(methods)(fileContent))
        }
      })

      // 4 -- Add chunks to the server after compiling
      chunks[keyName] = modules
    })
  }
}
Copy the code
  • The above code is not special description, in fact, loadr parsing file, file source

3.4 Implementation of compose function

function compose(resolveLoaders) {
  if (resolveLoaders.length === 0) return x= > x
  if (resolveLoaders.length === 1) return x= > resolveLoaders[0](x)
  return resolveLoaders.reduce((a, b) = > (. args) = >a(b(... args))) }Copy the code

The above code, without much elaboration, is essentially an implementation of compose, which we often write, using the source code for Redux

4. Conclusion

The above is the simple implementation of Webpack-flow, if not welcome correction

5. Source address and extension

  • The address of the above code is GitBub
  • In fact, xiaobian also wrote an article, you can refer to personal blog