preface
In-depth understanding of webpack packaging.
Module analysis
Node.js depends on the environment
- 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
- Write the bundler.js file
The following Babel needs to be installed
- Babel/Parser: Parse the contents of the file we read from fs.readfilesync and return AST (abstract syntax tree)
- Babel /traverse: Traverse the AST to get the necessary data
- Babel /core: The Babel core module has a method transformFromAst that converts the AST into code that the browser can run
- @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!