• 前端进阶特训营-TDD制造rollup-0



    11月22日
    然叔(夏然)带着大家写rollup, 全部采用TDD方式开发。
    rollup是什么?就是一个打包器。
    rollup适合类库场景,工程上使用webpack.

    mini-rollup项目分为6部分
    1.原型 Treeshaking,AST
    2.节点遍历器 Walk
    3.构造作用域 Scope
    4.模块分析函数 analyze
    5.单模块实例 Module
    6.打包器 Module,Bundle

    第一部分 原型 Treeshaking,AST
    Tree-shaking的本质是消除无用js代码。无用代码消除广泛存在于编译器中。编译器
    可以判断某些代码根本不影响输出,然后消除这些代码,这个称为DCE dead code elimination

    今天写个最简单的,先在单模块做,以后扩展到多模块。
    原型项目
    const a = () => 'a'
    const b = () => 'b'
    a()

    output:
    const a = () => 'a'
    a()
    其实就是把b过滤掉。

    如何做?
    1.构建语法树,剔除无用的部分?谁未用到谁就被踢掉。
    2.支持保存使用的代码?本来是有作用域的scope,现在可以先简单一些,只有一个全局作用域。

    模块分析相当于对读取的文件代码字符串进行解析。这一步其实和高级语言的编译过程一致。需要将模块
    解析为抽象语法树AST。我们借助babel/parser来完成。

    首先认识一下语法树
    AST Abstract Syntax Tree 抽象语法树 在计算机科学中,或简称语法树 Syntax tree,是源代码语法
    结构的一种抽象表示。它以树状的形式表现编程语言的语法结构,树上的每个节点都表示源代码中的
    一种结构。https://astexplorer.net

    分两层:1)文本生成对象。parse 2)针对对象进行各种遍历
    1.PARSE:
    const a = () => 'a'; 放到https://astexplorer.net
    const a = () => 'a';
    const b = () => 'b';
    抽象:就是把分隔符去掉,编程一个对象。
    2.TRANSFORM
    3.GENERATE

    const fs = require('fs')
    const acorn = require('acorn')
    const MagicSting = require('magic-string');
    -----------------------------------------------------
    开始手动编码:
    1.开始,先测试nodejs是否安装完毕
    index.js
    const fs = require('fs')
    const path = require('path')
    console.log('rollup')
    终端界面运行:
    node index.js
    可以打印出东西,说明nodejs已经安装。

    2.先安装一下语法树的库
    npm i acorn

    3.引入acorn来建立语法树
    const acorn = require('acorn')
    然后创建一个source.js文件,加入几行语法:
    const a = () => 'a';
    const b = () => 'b';
    a()
    然后开始读文件
    const code = fs.readFileSync('./src/source.js',"utf-8").toString()
    运行结果:
    node index.js
    rollup const a = () => 'a';
    const b = () => 'b';
    a()

    然后开始用acorn包parse读出的文件内容,形成语法树。
    const ast = acorn.parse(code, {
        locations: true,
        ranges: true,
        sourceType: 'module',
        ecmaVersion: 7
    })

    然后裁剪代码,裁剪用的magicstring做的,用这个库裁剪。
    npm i magic-string
    引入:
    const MagicString = require('magic-string')
    这是一个对象,需要new
    const m = new MagicString(code)
    m.snip(0,19)

    裁剪思路:
    1. 首先收集声明
    2. 在声明首次引用时把它放到引用前面

    const declarations ={} 
    把前两个node搞出来
    ast.body
    key:变量名
    value:节点
    就是一个循环+一个if判断
    ast.body.forEach( node => {
        if (node.type === 'VariableDeclaration') {
            declarations[node.declarations[0].id.name] = node
        }
    })

    调用a()时,把a的声明一起放到一个新数组中。
    首先定义一个新数组
    const statements = []
    ast.body
     .filter(node => node.type !== 'VariableDeclaration')
     .forEach(node => {
        statements.push(declarations[node.expression.callee.name])
        statements.push(node)
     })

    最后一步,将AST输出成代码
    MagicString根据statements输出打印即可
    statements.forEach((node) => {
        str += m.snip(node.start, node.end).toString()+'\n'
    }
    完成第一个程序。

    当前程序问题:
    1. 嵌套问题 -代码的层级问题
    const a = () => 'a';
    const b = () => 'b';
    if(true) {
        a()
    }
    2. 模块问题

    3.作用域
    function() {

    }
    4.Type问题

    5.语法问题
    ---------------------
    先解决代码层级问题
    if(true) {
        a()
    }
    如何找到a?
    开始做树的遍历
    安装单元测试
    npm i jest -g
    npm config get registry
    #最新地址 淘宝 NPM 镜像站喊你切换新域名啦!
    npm config set registry https://registry.npmmirror.com

    walk.js

    mkdir __tests__


    PS C:\film\front\rollup> jest 
     PASS  __tests__/walk.spec.js
      ast walk function
        √ single node (11 ms)                                                            
                                                                                         
    Test Suites: 1 passed, 1 total                                                       
    Tests:       1 passed, 1 total                                                       
    Snapshots:   0 total
    Time:        0.562 s
    Ran all test suites.

    jest ./__tests__/walk.spec.js

    VUE的源代码都有测试用例
    ----------------------------
    walk.js怎么写?


    理解单元测试的玩法
    -----------------------------
    正式步入测试驱动开发的时代

  • 相关阅读:
    数据结构之赫曼夫树(哈曼夫树)
    AtCoder Beginner Contest 278 G.Generalized Subtraction Game(思维题/博弈 multi-sg)
    es6_数组新增的遍历方法
    OpenCV Python – 使用SIFT算法实现两张图片的特征匹配
    如何搭建高效安全的eBay测评环境:步骤与要点解析
    bootstrap的相关知识点
    springboot基于JAVA的电影推荐系统的开发与实现毕业设计源码112306
    微信支付、微信公众号接口认证方案
    golang singleflight资料整理
    Re 爬取数据
  • 原文地址:https://blog.csdn.net/hb_zxl/article/details/138046656