What is the WebPack template code

After webPack wraps the project, we can see that our business code is wrapped in a piece of code. This piece of code is the Runtime code generated by WebPack, which I will refer to as webPack template code

Webpack does not generate files when code is cut

  • Sample directory structure
.Heavy Exercises ── Heavy Exercises. Md heavy Exercises ─ distPackage the build file│ ├ ─ ─ 1. Js# src/chunk.js => 1.js│ ├ ─ ─ app. Js# src/index.js => app.js│ └ ─ ─ splitChunk. Js# src/splitChunk.js => splitChunk.js├── Package. json ├─ SRC │ ├─ chunk.js# Dynamically loaded chunk│ ├ ─ ─ index. Js# Non-code cutting entry file│ └ ─ ─ splitChunk. Js# code cut entry file├ ─ ─ webpack. Config. Js └ ─ ─ yarn. The lockCopy the code
  • index.js
// index.js
console.log('app')
Copy the code
  • File after build
; (function(modules) {
  // webpackBootstrap
  // The module cache
  var installedModules = {}

  // The require function
  function __webpack_require__(moduleId) {
    // Check if module is in cache
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports
    }
    // Create a new module (and put it into the cache)
    var module = (installedModules[moduleId] = {
      i: moduleId,
      l: false.exports: {}})// Execute the module function
    modules[moduleId].call(module.exports, module.module.exports, __webpack_require__)

    // Flag the module as loaded
    module.l = true

    // Return the exports of the module
    return module.exports
  }

  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules

  // expose the module cache
  __webpack_require__.c = installedModules

  // define getter function for harmony exports
  __webpack_require__.d = function(exports, name, getter) {
    if(! __webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true.get: getter })
    }
  }

  // define __esModule on exports
  __webpack_require__.r = function(exports) {
    if (typeof Symbol! = ='undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module'})}Object.defineProperty(exports, '__esModule', { value: true})}// create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function(value, mode) {
    if (mode & 1) value = __webpack_require__(value)
    if (mode & 8) return value
    if (mode & 4 && typeof value === 'object' && value && value.__esModule) return value
    var ns = Object.create(null)
    __webpack_require__.r(ns)
    Object.defineProperty(ns, 'default', { enumerable: true.value: value })
    if (mode & 2 && typeofvalue ! ='string')
      for (var key in value)
        __webpack_require__.d(
          ns,
          key,
          function(key) {
            return value[key]
          }.bind(null, key)
        )
    return ns
  }

  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function(module) {
    var getter =
      module && module.__esModule
        ? function getDefault() {
            return module['default']} :function getModuleExports() {
            return module
          }
    __webpack_require__.d(getter, 'a', getter)
    return getter
  }

  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function(object, property) {
    return Object.prototype.hasOwnProperty.call(object, property)
  }

  // __webpack_public_path__
  __webpack_require__.p = ' '

  // Load entry module and return exports
  return __webpack_require__((__webpack_require__.s = 0))
})([
  /* 0 */
  function(module, exports) {
    /* Here is the index.js package */
    console.log('app')})Copy the code
  • As you can see, the above code is mostly generated__webpack_require__Function related stuff,__webpack_require__The webPack Runtime is the way to load internal modules
  • The generated code is the immediate execution function expression (IIFE). The immediate execution function’s call parameters are all the modules that WebPack processes, usually a file into a module. Modules can be an object or an array. The key value of the object is the module path or module ID, and the value is the specific code of the module. Is an array, the array subscript is the module ID
  • You can see that the module is passed three arguments when it is loaded, namelymodule,exportsand__webpack_require__

The above code can be simplified as follows

; (function(modules) {
  // Used to cache loaded modules
  var installedModules = {}

  // The method to load the module
  function __webpack_require__(moduleId) {
    // If the module exists in the cache, return it directly
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports
    }
    // Define a new module object and store it in the cache
    var module = (installedModules[moduleId] = {
      i: moduleId,
      l: false.exports: {}})// Load the module
    modules[moduleId].call(module.exports, module.module.exports, __webpack_require__)

    // Module loading completion flag
    module.l = true

    // Returns the object exported by the module
    return module.exports
  }

  // Load the entry module
  return __webpack_require__(0)
})([
  /* 0 */
  function(module, exports) {
    /* Here is the index.js package */
    console.log('app')})Copy the code

Webpack has generated files when code is cut

  • splitChunk.js
// splitChunk.js
import('./chunk').then(chunk= > {
  chunk.default()
  console.log('done')})Copy the code
  • chunk.js
// chunk.js
export default() = > {console.log('I am chunk')}Copy the code
  • After the build generatedsplitChunk.jsfile
; (function(modules) {
  // webpackBootstrap
  // install a JSONP callback for chunk loading
  function webpackJsonpCallback(data) {
    var chunkIds = data[0]
    var moreModules = data[1]

    // add "moreModules" to the modules object,
    // then flag all "chunkIds" as loaded and fire callback
    var moduleId,
      chunkId,
      i = 0,
      resolves = []
    for (; i < chunkIds.length; i++) {
      chunkId = chunkIds[i]
      if (installedChunks[chunkId]) {
        resolves.push(installedChunks[chunkId][0])
      }
      installedChunks[chunkId] = 0
    }
    for (moduleId in moreModules) {
      if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
        modules[moduleId] = moreModules[moduleId]
      }
    }
    if (parentJsonpFunction) parentJsonpFunction(data)

    while (resolves.length) {
      resolves.shift()()
    }
  }

  // The module cache
  var installedModules = {}

  // object to store loaded and loading chunks
  // undefined = chunk not loaded, null = chunk preloaded/prefetched
  // Promise = chunk loading, 0 = chunk loaded
  var installedChunks = {
    0: 0
  }

  // script path function
  function jsonpScriptSrc(chunkId) {
    return __webpack_require__.p + ' ' + ({}[chunkId] || chunkId) + '.js'
  }

  // The require function
  function __webpack_require__(moduleId) {
    // Check if module is in cache
    if (installedModules[moduleId]) {
      return installedModules[moduleId].exports
    }
    // Create a new module (and put it into the cache)
    var module = (installedModules[moduleId] = {
      i: moduleId,
      l: false.exports: {}})// Execute the module function
    modules[moduleId].call(module.exports, module.module.exports, __webpack_require__)

    // Flag the module as loaded
    module.l = true

    // Return the exports of the module
    return module.exports
  }

  // This file contains only the entry chunk.
  // The chunk loading function for additional chunks
  __webpack_require__.e = function requireEnsure(chunkId) {
    var promises = []

    // JSONP chunk loading for javascript

    var installedChunkData = installedChunks[chunkId]
    if(installedChunkData ! = =0) {
      // 0 means "already installed".

      // a Promise means "currently loading".
      if (installedChunkData) {
        promises.push(installedChunkData[2])}else {
        // setup Promise in chunk cache
        var promise = new Promise(function(resolve, reject) {
          installedChunkData = installedChunks[chunkId] = [resolve, reject]
        })
        promises.push((installedChunkData[2] = promise))

        // start chunk loading
        var script = document.createElement('script')
        var onScriptComplete

        script.charset = 'utf-8'
        script.timeout = 120
        if (__webpack_require__.nc) {
          script.setAttribute('nonce', __webpack_require__.nc)
        }
        script.src = jsonpScriptSrc(chunkId)

        // create error before stack unwound to get useful stacktrace later
        var error = new Error()
        onScriptComplete = function(event) {
          // avoid mem leaks in IE.
          script.onerror = script.onload = null
          clearTimeout(timeout)
          var chunk = installedChunks[chunkId]
          if(chunk ! = =0) {
            if (chunk) {
              var errorType = event && (event.type === 'load' ? 'missing' : event.type)
              var realSrc = event && event.target && event.target.src
              error.message = 'Loading chunk ' + chunkId + ' failed.\n(' + errorType + ':' + realSrc + ') '
              error.name = 'ChunkLoadError'
              error.type = errorType
              error.request = realSrc
              chunk[1](error)
            }
            installedChunks[chunkId] = undefined}}var timeout = setTimeout(function() {
          onScriptComplete({ type: 'timeout'.target: script })
        }, 120000)
        script.onerror = script.onload = onScriptComplete
        document.head.appendChild(script)
      }
    }
    return Promise.all(promises)
  }

  // expose the modules object (__webpack_modules__)
  __webpack_require__.m = modules

  // expose the module cache
  __webpack_require__.c = installedModules

  // define getter function for harmony exports
  __webpack_require__.d = function(exports, name, getter) {
    if(! __webpack_require__.o(exports, name)) {Object.defineProperty(exports, name, { enumerable: true.get: getter })
    }
  }

  // define __esModule on exports
  __webpack_require__.r = function(exports) {
    if (typeof Symbol! = ='undefined' && Symbol.toStringTag) {
      Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module'})}Object.defineProperty(exports, '__esModule', { value: true})}// create a fake namespace object
  // mode & 1: value is a module id, require it
  // mode & 2: merge all properties of value into the ns
  // mode & 4: return value when already ns object
  // mode & 8|1: behave like require
  __webpack_require__.t = function(value, mode) {
    if (mode & 1) value = __webpack_require__(value)
    if (mode & 8) return value
    if (mode & 4 && typeof value === 'object' && value && value.__esModule) return value
    var ns = Object.create(null)
    __webpack_require__.r(ns)
    Object.defineProperty(ns, 'default', { enumerable: true.value: value })
    if (mode & 2 && typeofvalue ! ='string')
      for (var key in value)
        __webpack_require__.d(
          ns,
          key,
          function(key) {
            return value[key]
          }.bind(null, key)
        )
    return ns
  }

  // getDefaultExport function for compatibility with non-harmony modules
  __webpack_require__.n = function(module) {
    var getter =
      module && module.__esModule
        ? function getDefault() {
            return module['default']} :function getModuleExports() {
            return module
          }
    __webpack_require__.d(getter, 'a', getter)
    return getter
  }

  // Object.prototype.hasOwnProperty.call
  __webpack_require__.o = function(object, property) {
    return Object.prototype.hasOwnProperty.call(object, property)
  }

  // __webpack_public_path__
  __webpack_require__.p = ' '

  // on error function for async loading
  __webpack_require__.oe = function(err) {
    console.error(err)
    throw err
  }

  var jsonpArray = (window['webpackJsonp'] = window['webpackJsonp'] | | [])var oldJsonpFunction = jsonpArray.push.bind(jsonpArray)
  jsonpArray.push = webpackJsonpCallback
  jsonpArray = jsonpArray.slice()
  for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i])
  var parentJsonpFunction = oldJsonpFunction

  // Load entry module and return exports
  return __webpack_require__((__webpack_require__.s = 0))
})([
  /* 0 */
  function(module, exports, __webpack_require__) {
    __webpack_require__
      .e(1)
      .then(__webpack_require__.bind(null.1))
      .then(chunk= > {
        chunk.default()
        console.log('done')})})Copy the code
  • With no previous code cut, the main is much morewebpackJsonpCallbackand__webpack_require__.efunction
  • The simplified code is as follows
; (function(modules) {
  // the callback executes after the js is loaded
  // A chunk clock can contain many modules
  function webpackJsonpCallback(data) {}

  // Chunk that has been loaded
  // a chunk value of 0 indicates that the chunk has been loaded
  var installedChunks = {
    0: 0
  }

  / / the require module
  function __webpack_require__(moduleId) {}
  // Load the js file and insert the script tag
  __webpack_require__.e = function requireEnsure(chunkId) {}

  // Read modules already in webpackJsonp for use in code
  var jsonpArray = (window['webpackJsonp'] = window['webpackJsonp'] | | [])var oldJsonpFunction = jsonpArray.push.bind(jsonpArray)
  // Change the push method to a callback for this module
  jsonpArray.push = webpackJsonpCallback
  jsonpArray = jsonpArray.slice()
  for (var i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i])
  var parentJsonpFunction = oldJsonpFunction

  return __webpack_require__((__webpack_require__.s = 0))
})([
  /* 0 */
  function(module, exports, __webpack_require__) {
    __webpack_require__
      .e(1) // Insert the asynchronous JS script tag
      // The webPackJsonP.push method is automatically executed after the loaded JS is successfully loaded
      // Register the module with modules
      // Load the module
      .then(__webpack_require__.bind(null.1))
      .then(chunk= > {
        chunk.default()
        console.log('done')})})Copy the code
  • After packaging1.jscontent
; (window['webpackJsonp'] = window['webpackJsonp'] || []).push([
  [1], [,/* 0 */
    / * 1 * /
    function(module, __webpack_exports__, __webpack_require__) {
      'use strict'
      __webpack_require__.r(__webpack_exports__)
      __webpack_exports__['default'] = (a)= > {
        console.log('I am chunk'}}]])Copy the code
  • Code cut after different file sharing modules are implemented through global variableswebpackJsonpTo implement the
  • After the asynchronous JS file is loaded successfully, the execution code will be stopped, and the execution code iswindow['webpackJsonp'].pushMethod, the actual function executed issplitChunk.jsIn thewebpackJsonpCallbackmethods
  • The simple execution process is as follows

Extract the WebPack Runtime to a separate file

Set webpack configuration optimization. RuntimeChunk is true, then the webpack generated template files into a separate file, all other files will be in the form of separation for the json file

Implement a simple Webpack module loading function

The __webpack_require__ and window[‘webpackJsonp’].push methods are implemented in webpack-require

  • index.js
; (function(modules) {
  // Cache modules already required
  const installedModules = {}
  // Load the module
  function __webpack_require__(id) {
    if (installedModules[id]) {
      return installedModules[id].exports
    }
    const module = (installedModules[id] = {
      loaded: false.exports: {}
    })
    modules[id].call(module.exports, module.module.exports, __webpack_require__)
    // Indicate that the module has been loaded
    module.loaded = true
    return module.exports
  }

  // Cache the chunk that has been loaded
  const installedChunks = {}

  // Callback executed after the js chunk file is successfully loaded
  function webpackJsonpCallback(data) {
    // Name of chunk that exists in the js file
    const chunkIds = data[0]
    // Module exported from chunk
    const moreModules = data[1]

    const resolves = []

    // Let all chunks contained in a js file complete loading
    // A single js file may contain multiple pre-packaged files
    for (i = 0; i < chunkIds.length; i++) {
      const chunkId = chunkIds[i]
      if (installedChunks[chunkId]) {
        resolves.push(installedChunks[chunkId][0])
      }
      installedChunks[chunkId] = 0
    }

    // Copy the modules in chunk
    for (let moduleId in moreModules) {
      if (Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
        modules[moduleId] = moreModules[moduleId]
      }
    }

    // let __webpack_require__.e execute the returned promise all resolve
    while (resolves.length) {
      resolves.shift()()
    }
  }

  // Load modules that already exist in window.webPackjsonp
  const jsonpArray = (window.webpackJsonp = window.webpackJsonp || [])
  jsonpArray.push = webpackJsonpCallback
  for (let i = 0; i < jsonpArray.length; i++) webpackJsonpCallback(jsonpArray[i])

  // Insert the script tag
  __webpack_require__.e = function(chunkId) {
    const promises = []
    let installedChunkData = installedChunks[chunkId]
    // If it has been cached, return it directly
    if (installedChunkData === 0) return Promise.all(promises)
    if (installedChunkData) {
      // The loading condition
      promises.push(installedChunkData[2])}else {
      // New load
      const promise = new Promise((resolve, reject) = > {
        installedChunkData = installedChunks[chunkId] = [resolve, reject]
      })
      installedChunkData[2] = promise
      promises.push(promise)
      const script = document.createElement('script')

      // Convert to url according to chunkId
      const chunksSrc = {
        './chunk.js': './chunk.js'.'./chunks-1.js': './chunks.js'.'./chunks-2.js': './chunks.js'
      }
      script.src = chunksSrc[chunkId]

      // js complete loading event
      onScriptComplete = function(event) {
        clearTimeout(timeout)
        // Avoid IE memory leaks
        script.onerror = script.onload = null
        // The load failed when the chunk was not completed
        const chunk = installedChunks[chunkId]
        if(chunk ! = =0) {
          if (chunk) {
            chunk[1] (`${chunkId}Load failed ')
          }
          installedChunks[chunkId] = undefined
        }
      }
      script.onerror = script.onload = onScriptComplete
      // Set timeout
      const timeout = setTimeout((a)= > onScriptComplete(), 120000)
      document.head.appendChild(script)
    }
    return Promise.all(promises)
  }

  // Load the entry file
  return __webpack_require__('./index.js') ({})'./index.js': function(module, exports, __webpack_require__) {
    console.log('I am index.js')

    / / load. / the chunk. Js
    __webpack_require__
      .e('./chunk.js')
      .then((a)= > __webpack_require__('./chunk.js'))
      .then(data= > {
        data.default()
      })

    / / load. / chunks - 1. Js
    __webpack_require__
      .e('./chunks-1.js')
      .then((a)= > __webpack_require__('./chunks-1.js'))
      .then(data= > {
        data.default()
      })

    / / load. / chunks - 2. Js
    __webpack_require__
      .e('./chunks-2.js')
      .then((a)= > __webpack_require__('./chunks-2.js'))
      .then(data= > {
        data.default()
      })
  }
})
Copy the code
  • chunk.js
; (window['webpackJsonp'] = window['webpackJsonp'] || []).push([
  ['./chunk.js'] and {'./chunk.js': function(module, __webpack_exports__, __webpack_require__) {
      'use strict'
      __webpack_exports__['default'] = (a)= > {
        console.log('I am chunk'}}}])Copy the code
  • chunks.js
// A file contains multiple chunks; (window['webpackJsonp'] = window['webpackJsonp'] || []).push([
  ['./chunks-1.js'.'./chunks-2.js'] and {'./chunks-1.js': function(module, __webpack_exports__, __webpack_require__) {
      'use strict'
      __webpack_exports__['default'] = (a)= > {
        console.log('I am chunks-1')}},'./chunks-2.js': function(module, __webpack_exports__, __webpack_require__) {
      'use strict'
      __webpack_exports__['default'] = (a)= > {
        console.log('I am chunks-2'}}}])Copy the code

link

This article is simultaneously posted to Github, and the sample code is available on Github

  • Webpack principles series of articles
  • Webpack principles – Start with front-end modularity