90 lines of code to implement the module packer

Magician Carson 2021-09-15 09:05:06

Welcome to join Human high quality front end Framework Research Group , Take flight

Hello everyone , I'm Carson .

Today, let's talk about how to use 90 Line of code to achieve a modern JS Module packer .

Our packer is mini , But it did webpack Core functions .

and , I know you have a headache when you see large pieces of code , So this article is all pictures . After reading, if you are interested , Here is Warehouse address of complete code , Only 90 Line code .

Let's start happily .

Generate dependency graph

If the application is a ball of wool , Then the entry file is the thread header . The first thing the packer does is :

Start to filter the direction of the whole line along the end of the line

Suppose the entry file is entry.js

// entry.js
import a from './a.js';
import b from './b.js';
console.log(a, b);
 Copy code 

He depends on a.js And b.js.

em... It's a little too simple , Let's expand a.js And b.js

// a.js
import c from './c.js';
// ...
 Copy code 
// b.js
import d from './d.js';
import e from './e.js';
// ...
 Copy code 

So the whole dependency is like this :

The packer starts with the entry file , Trying to build a module ( namely js file ) The dependency between , That's what we just talked about Start to filter the direction of the whole line along the end of the line .

The dependencies between modules can be analyzed by import Statement statement hear .

In order to analyze import Statement statement , have access to babel And other compilation tools decompose the module code into AST( Abstract syntax tree ).

Traverse AST, The type is ImportDeclaration The node of is import Statement statement .

Last , We will AST Re convert to executable Object code , It may also need to be based on the hosting environment in which the code is to be executed ( It's usually a browser ) Do some conversion to the code .

such as , Browser does not support import './a.js' In this way ESM grammar , Then we need to put all ESM Grammatical transformation CJS grammar .

// Source code 
import './a.js';
// After the transformation 
 Copy code 

therefore , For the first mock exam (js file ), Will experience :

Right contains Object code and Dependencies between modules The data structure of is called asset.

Every asset Can pass Dependencies between modules Find the dependent module , Repeat the process , Generate a new asset, Finally, the whole application is formed asset The dependency between :

Applying complete dependencies is called Dependency graph (dependency graph).

Packaging code

Next , Just traverse Dependency graph , Will all asset Of Object code Just pack it together .

All the code will be packaged in one Immediate execution function in :

(function(modules) {
// Packaged code 
 Copy code 

modules All are saved in asset And their dependencies .

If you are right about modules Interested in the details of , You can turn the code in the warehouse at the end of the text

Just said ,asset Of Object code yes CJS canonical , similar :

// entry.js
 Copy code 

This means that we need to achieve :

  • require Method ( Other methods for introducing dependencies asset Of Object code

  • module object ( Used to save the current asset Of Object code Data exported after execution )

meanwhile , In order to prevent different asset Of Object code The variables in the are contaminated with each other , Every Object code A separate scope is required .

We will Object code Wrapped in function in :

// We operate on string templates 
`function (require, module, exports) { ${asset.code} }`
 Copy code 

therefore , The final packaging result is :

(function(modules) {
function require() {// ...}
require( entrance asset Of ID)
 Copy code 

This string is wrapped in the browser <script> tag , Will execute in turn :

  1. require( entrance asset Of ID), perform entrance asset Of Object code

  2. Object code Internally it will call require Carry out other asset Of Object code

  3. Step by step ...


The packer works in two steps :

  1. Start traversing from the entry file , Generate Dependency graph

  2. According to dependency graph , Package the code into a Immediate execution function

This packer is still very young , Missing many necessary functions , such as :

  • Resolve circular dependency
  • cache

But the flaws don't hide the virtues ~

Please bring the original link to reprint ,thank
Similar articles