preface

In-depth understanding of webpack packaging.

Module analysis

Node.js depends on the environment

  1. Create file, the simplest string concatenation
// index.js

import { message } from './message.js'
console.log(message)

// message.js

import { word } from './word.js'
export const message = `say ${ word }`

// word.js

export const word = 'hello world ! '
Copy the code
  1. Write the bundler.js file

The following Babel needs to be installed

  1. Babel/Parser: Parse the contents of the file we read from fs.readfilesync and return AST (abstract syntax tree)
  2. Babel /traverse: Traverse the AST to get the necessary data
  3. Babel /core: The Babel core module has a method transformFromAst that converts the AST into code that the browser can run
  4. @babel/preset-env: Convert code to ES5 code
const fs = require('fs');
const path = require('path')
const parser = require('@babel/parser'); // help us parse string blocks, that is, import, which we encountered when reading files through fs.exportConst traverse = require('@babel/traverse'Default const Babel = require().default // traverse with ES Module for requier'@babel/core');

const moduleAnalyser = (filename) => {
	const content = fs.readFileSync(filename, 'utf-8'); // Parser returns an AST (abstract syntax tree) const AST = parser.parse(content, {parser)sourceType: "module"} const dependencies = {}; Traverse (AST, {ImportDeclaration({node}) { Node denotes children of these nodes const dirname = path.dirname(filename); // The path we take from the abstract syntax tree is a relative path, and then we need to process it to properly use const newDirname = in bundler.js'/' + path.join(dirname, node.source.value).replace('\ \'.'/'); // Generate absolute path dependencies[node.source.value] = newDirname; Const {code} = babel.transformFromast (AST, null, const {code} = babel.transformFromast (AST, null, { presets: ['@babel/preset-env']})return{filename, dependencies, code}} Const makeDependenciesGraph = (Entry) => {const entryModule = moduleAnalyser(Entry) const graghArray = [ entryModule ]; // First put the results of the entry file we analyzed into the atlas arrayfor (leti = 0; i < graghArray.length; i ++) { const item = graghArray[i]; const { dependencies } = item; // Get the module on which the current module dependsif (dependencies) {
			for ( let j inDependencies) {// PassforGragharray.push (moduleAnalyser(dependencies[J])); }}} const gragh = {}; Gragharray.foreach (item => {gragh[item.filename] = {dependencies: item.dependencies, code: item.code } })return gragh;
}

const graghInfo = makeDependenciesGraph('./src/index.js')

console.log(graghInfo)

Copy the code

The data structure of graghArray is shown below

  • Generate runnable code

Create the function that generates the code, pass the path to our intersection file, and integrate the previous code.

Const generateCode = (entry) => { Const gragh = json.stringify (makeDependenciesGraph(entry)); // We know that Webpack executes all our modules in a closure, so we write a self-executing function // note: The code we generated used require and exports to introduce export modules that our browser didn't know about, so we needed to build such functionsreturn `
		(function( gragh ) {
			functionRequire (module) {// Convert relative paths to absolute pathsfunction localRequire(relativePath) {
					return require(gragh[module].dependencies[relativePath])
				}
				const exports = {};
				(function( require, exports, code ) {
					eval(code)
				})( localRequire, exports, gragh[module].code )

				return exports;
			}
			require('${ entry }')
		})(${ gragh })
	`;
}

const code = generateCode('./src/index.js');

console.log(code)
Copy the code

conclusion

When you put the code together and run it on the command line, you print out a piece of code and copy it to run in your browser.

And you’re done!