preface

Generally our front-end engineering is unable to do without Webpack, we do not have too much resistance to the principle of Webpack, now to manually implement a very simple Webpack, a preliminary understanding of the construction process of Webpack.

The use of webpack4. X

1. After NPM init -y, install webpack webpack-CLI

NPM I [email protected] [email protected] -d

2. Create webpack.config.js, index.js, greeting.js

// webpack.config.js
const path = require('path')
module.exports = {
  entry: './src/index.js'.mode: 'development'.output: {
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'}}// index.js
import { greeting } from './greeting.js'
document.write(greeting('Jane'))

// greeting.js
export function greeting(name) {
  return 'hello ' + name
}
Copy the code

3. Build packaged, compact code

 (function(modules) {
 	var installedModules = {}; // Cache dependency
         // Implement the require method.
 	function __webpack_require__(moduleId) {
                // The module is already required, using the cache directly.
		if(installedModules[moduleId]) {
 			return installedModules[moduleId].exports;
 		}
 		var module = installedModules[moduleId] = {
 			i: moduleId,
 			l: false.exports: {}};// recursively call require to build the dependency tree
 		modules[moduleId].call(module.exports, module.module.exports, __webpack_require__);
 		module.l = true;
                // Returns the result of reuqire
 		return module.exports;
 	}
        // Start from the entry file.
 	return __webpack_require__(__webpack_require__.s = "./src/index.js"); ({})"./src/greeting.js": function(module, __webpack_exports__, __webpack_require__) {

"use strict";
function greeting(name) { return 'hello ' + name}
},
"./src/index.js": function(module, __webpack_exports__, __webpack_require__) {
  "use strict";
  var _greeting_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__("./src/greeting.js");
  document.write(Object(_greeting_js__WEBPACK_IMPORTED_MODULE_0__["greeting"]) ('Jane'))}});Copy the code

The realization of the webpack

Business code

The SRC code and webpack.config.js are the same as above

// webpack.config.js
const path = require('path')
module.exports = {
  entry: './src/index.js'.mode: 'development'.output: {
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'}}// index.js
import { greeting } from './greeting.js'
document.write(greeting('Jane'))

// greeting.js
export function greeting(name) {
  return 'hello ' + name
}
Copy the code

The implementation code

Create a lib folder to hold the WebPack implementation code

index.js

const  Compiler = require('./compiler')
const options = require('.. /webpack.config.js')
const compiler = new Compiler(options).run()
Copy the code

parse.js

npm i @babel/preset-env babel-core babel-preset-env babel-traverse babylon

  • The string is first read through FS and converted into an AST tree through the Babel plug-in
  • Traverse to get the path of the REQUIRE in the AST
  • Convert the AST syntax tree to ES5 code via babel-core
const fs = require('fs')
// Convert string code to AST
const babylon = require('babylon')
// Get each module dependency
const traverse = require('babel-traverse').default
// Convert ast code to JS code
const { transformFromAst }  = require('babel-core')

module.exports = {
  getAST: (path) = > {
    const source = fs.readFileSync(path, 'utf-8')

    return babylon.parse(source, {
      sourceType: 'module'})},getDependencies: (ast) = >{
    const dependencies = []
    traverse(ast, {
      ImportDeclaration: ({node}) = >{
        dependencies.push(node.source.value)
      }
    })
    return dependencies
  },
  transform: (ast) = >{
    const {code} = transformFromAst(ast,null, {presets: ['env']})return code
  }
}
Copy the code

compiler.js

  • Start building from the entry file
  • Generate entry files generate three types of data, AST, ES5 code, dependent paths
  • Recursively generate these three types of data based on their dependent paths and collect them all into a Modules array
  • Finally, the file packed with parameter webpack4.x is stored in an object with the file path as the key and the module code source as the value, passing in the self-executing function as an argument.
const {getAST, getDependencies, transform}= require('./parse')
const path = require('path')
const fs = require('fs')

module.exports= class Compiler {

  constructor(options) {
    // Get configuration parameters
    const { entry, output } = options
    this.entry = entry
    this.output = output
    this.modules = []
  }
  / / run
  run(){
    // Build from the entrance
    const entryModule = this.buildModule(this.entry, true)
    this.modules.push(entryModule)
    this.modules.map(_module= >{
      _module.dependencies.map(dependency= >{
        this.modules.push(this.buildModule(dependency))
      })
    })
    this.emitFiles()
  }
  
  // Build a module that generates THE ES6 code into an AST, generates the ES5 code from the AST tree, and returns the dependencies
  buildModule(filename, isEntry){
    let ast
    if(isEntry) {
      ast = getAST(filename)
    } else {
      const absoultePath = path.join(process.cwd(), './src',filename)
      ast = getAST(absoultePath)
    }
    return {
      filename,
      dependencies: getDependencies(ast),
      source: transform(ast)
    }
  }

  // After the dependency tree is generated, output to the specified directory
  emitFiles(){
    const outputpath = path.join(this.output.path, this.output.filename)
    const list = this.modules.map(_module= >{
      return (`
      '${_module.filename}': function(module, exports, require){
        ${_module.source}
      }
      `)})let modules = list.join(', ')
    const bundle = `(function(modules){
      var installedModules = {}
      function __webpack_require__(filename){
        if(installedModules[filename]) {
          return installedModules[filename].exports
        }
        var module = installedModules[filename] = {
          i: filename,
          l: false,
          exports: {}
        }
        modules[filename].call(module.exports, module, module.exports, __webpack_require__)
        module.l = true
        return module.exports
      }
      __webpack_require__('The ${this.entry}') ({})${modules}}) `;
    console.log(bundle);
    fs.writeFileSync(outputpath, bundle, 'utf-8')}}Copy the code

The generated code

node ./lib/index.js

(function(modules){
      var installedModules = {}
      function __webpack_require__(filename){
        if(installedModules[filename]) {
          return installedModules[filename].exports
        }
        var module = installedModules[filename] = {
          i: filename,
          l: false.exports: {}
        }
        modules[filename].call(module.exports, module.module.exports, __webpack_require__)
        module.l = true
        return module.exports
      }
      __webpack_require__('/Users/openlee/Desktop/simplepack/src/index.js') ({})'/Users/openlee/Desktop/simplepack/src/index.js': function(module.exports.require){
        "use strict";
        var _greeting = require("./greeting.js");
        document.write((0, _greeting.greeting)('Jane')); },'./greeting.js': function(module.exports.require){
        "use strict";

Object.defineProperty(exports."__esModule", {
  value: true
});
exports.greeting = greeting;
function greeting(name) {
  return 'hello '+ name; }}})Copy the code

The end of the

Finally, welcome to pass by the old iron people praise ~