22
头图

Hi everyone, I'm Kasong.

JS talk about how to implement a modern 0613978c2efd2c module packager with 90 lines of code.

Although our packer is mini, it implements the core function webpack

Moreover, I know that you have a headache when you see a large section of code, so this article is all pictures. After reading interested, here is the warehouse address the complete code of , only 90 lines of code oh.

Let's start happily.

Generate dependency graph

If the application is a ball of yarn, then the entry file is the thread head. The first thing the packer has to do is:

Follow the end of the thread and start filtering the direction of the entire line

Assuming that the entry file is entry.js :

// entry.js

import a from './a.js';
import b from './b.js';

console.log(a, b);

He relied on a.js and b.js .

em... It's a bit too crude, let's expand on a.js and b.js :

// a.js
import c from './c.js';

// ...
// b.js
import d from './d.js';
import e from './e.js';

// ...

So the whole dependency is like this:

The packager will start from the entry file and try to establish js file), which is the we just talked about and start to filter the whole line along the line to .

The dependencies between modules can be learned import statement in the module code.

In order to analyze Import declaration can be used babel other compiler tools module code into AST (abstract syntax tree).

Traverse AST , the node of ImportDeclaration import statement.

Finally, we re-convert AST target code. It may be necessary to perform some conversions on the code according to the host environment (usually a browser) where the code will be executed.

For example, the browser does not support import './a.js' syntax such as ESM , then we need to convert all ESM syntax to CJS syntax.

// 源代码
import './a.js';

// 转换后
require('./a.js');

Therefore, for any module ( js file), you will experience:

The data structure on the right containing the dependency between object code and the asset .

Each asset can find dependent modules through the dependencies between modules, repeat this process to generate a new asset , and finally form all the dependencies between asset

The complete dependency of the application is called dependency graph (dependency graph).

Package code

Next, need only to traverse dependency FIG , all asset the packaged object code together on the line.

All the code will be packed in a immediate execution function :

(function(modules) {
  // 打包好的代码
})(modules)

modules saves all asset and their dependencies.

If you modules , you can go to the warehouse at the end of the article to read the code

Just said, asset of object code is CJS specification, like this:

// entry.js

require('./a.js');
require('./b.js');

This means we need to achieve:

  • require object code asset used to introduce dependencies)
  • module object (used to save the data exported after the execution of the asset object code of

At the same time, in order to prevent the variables in target codes asset from polluting each other, each target code needs an independent scope.

We wrap the target code function:

// 我们操作的是字符串模版
`function (require, module, exports) {
  ${asset.code}
}`

Therefore, the final packaged result is:

(function(modules) {
  function require() {// ...}
  
  require(入口asset的ID)
})(modules)

This string is wrapped in the browser <script> tag and will be executed in sequence:

  1. require (the ID of the entry asset), execute the object code of the entry asset
  2. target internal code calls require perform other asset of object code
  3. Go on step by step...

Summarize

The working principle of the packer is divided into two steps:

  1. Start traversing from the entry file, and generate dependency graph
  2. According to the dependency graph, package the code into a to execute the function

This packager is still very immature, missing many necessary functions, such as:

  • Resolve circular dependencies
  • Cache

But don’t you hide your flaws~

Welcome to join the human high-quality front-end framework research group , take flight

卡颂
3.1k 声望16.7k 粉丝