소스는 바벨을 해결

우리는 직접 프로젝트를 생성하고 실행합니다

npm install -D @babel/cli

우리는 최신 버전 7.8.0을 사용

test1.js 테스트를 만들기 :

/* test.js */
const fn = () => {}
new Promise(() => {})
class Test {}
const c = [1, 2, 3].includes(1)
//测试插件1
var a=10;

바벨 프로파일 .babelrc을 (모든 구성을 작성하지 않는) 만들기 :

/* .babelrc */
{
 
}

그럼 우리가 실행 :

npx babel test1.js -o test1.babel.js --config-file .babelrc

마지막으로, 결과 test1.babel.js 보면 :

/* test.js */
const fn = () => {};

new Promise(() => {});

class Test {}

const c = [1, 2, 3].includes(1); //测试插件1

var a = 10;

오? 왜 전혀 변경하지? 질문으로 우리는 소스 코드를 보면 -

바벨의 소스 더 나은 연구하기 위해, 우리는 github의 복제로 직접 이동 :

git clone https://github.com/babel/babel.git

그런 다음 우리는 실행할 때 :

npx babel test1.js -o test1.babel.js --config-file 

때 우리는 직접 개방 패키지 / 바벨 - CLI / 빈 / babel.js :

#!/usr/bin/env node

require("../lib/babel");

패키지 / 바벨 - CLI / SRC / 바벨 /하는 index.js :

#!/usr/bin/env node

import parseArgv from "./options";
import dirCommand from "./dir";
import fileCommand from "./file";

const opts = parseArgv(process.argv);

if (opts) {
  const fn = opts.cliOptions.outDir ? dirCommand : fileCommand;
  fn(opts).catch(err => {
    console.error(err);
    process.exitCode = 1;
  });
} else {
  process.exitCode = 2;
}

패키지 / 바벨 - CLI / SRC / 바벨 / file.js :

export default async function({
  cliOptions,
  babelOptions,
}: CmdOptions): Promise<void> {
	 if (cliOptions.filenames.length) {
    await files(cliOptions.filenames);
  } else {
    await stdin();
  }
}

그런 다음 파일 방법을 실행합니다

 async function files(filenames: Array<string>): Promise<void> {
    if (!cliOptions.skipInitialBuild) {
      await walk(filenames);
    }

그리고 도보 방법을 수행합니다

async function walk(filenames: Array<string>): Promise<void> {
    
        try {
          return await util.compile(
          );
        } catch (err) {
       
    );
  }

우리는 UTIL 컴파일 방법의 최종 구현을 볼 수 있습니다 (패키지 / 바벨 - CLI / SRC / 바벨 / util.js) :

export function compile(
  filename: string,
  opts: Object | Function,
): Promise<Object> {
  opts = {
    ...opts,
    caller: CALLER,
  };

  return new Promise((resolve, reject) => {
    babel.transformFile(filename, opts, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

그것은 바벨-CLI 후에 볼 수있다, 우리는 전달 된 매개 변수를 얻을 :

  1. 소스 파일 test1.js
  2. 파일 test1.babel.js를 입력
  3. 바벨 프로필 .babelrc
npx babel test1.js -o test1.babel.js --config-file .babelrc

컴파일 된 코드는 그 다음 상기 방법 babel.transformFile 바벨의 코어에 의해 취득하고, 마지막으로 컴파일 된 코드 -o 마지막 구성의 출력 바벨-cli를 통과한다.

우리는 무엇을 babel.transformFile 방법에 초점 그래서

패키지 / 바벨 - 코어 / SRC /하는 index.js :

export {
  transformFile
} from "./transform-file";
const transformFileRunner = gensync<[string, ?InputOptions], FileResult | null>(
	//加载配置文件
    const config: ResolvedConfig | null = yield* loadConfig(options);
    if (config === null) return null;
	//加载源文件
    const code = yield* fs.readFile(filename, "utf8");
    //开始编译
    return yield* run(config, code);
  },
);

loadConfig 방법에 대한하자의 이야기는, 사전 설정, 플러그인은 플러그인의 집합입니다, 우리가 그것을 변경하려고 사전에 플러그인의 집합입니다 우리는 플러그인 속성을 사용하여 사전 설정을 내부로 들어가 다음 파일을 읽고 후,하지 .babelrc 통과 기억 우리 .babelrc 구성 파일 :

/* .babelrc */
{
  "presets": [
    ["@babel/preset-env", {
      "modules": false,
      "useBuiltIns": "usage",
      "targets": "ie >= 8"
    }]
  ],
  "plugins": [
    ["@babel/plugin-transform-runtime", {
      "corejs":false
    }],
    ["./plugins/PluginTest1.js"]
  ]
}

그런 다음 실행 :

npx babel test1.js -o test1.babel.js --config-file .babelrc

결과 :

import "core-js/modules/es7.array.includes";
import "core-js/modules/es6.string.includes";
import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
import "core-js/modules/es6.promise";

/* test.js */
var fn = function fn() {};

new Promise(function () {});

var Test = function Test() {
  _classCallCheck(this, Test);
};

var c = [1, 2, 3].includes(1); //测试插件1

var aaa = 10;

구성 파일에 대한, 우리는 천천히 도입 플러그인과 prestes, 우리는 바벨 코어 봐 계속 우리의 구성 파일을로드하는 방법입니다.
바벨 코어 / SRC / 설정 / full.js :

export default gensync<[any], ResolvedConfig | null>(function* loadFullConfig(
  inputOpts: mixed,
): Handler<ResolvedConfig | null> {
  const result = yield* loadPrivatePartialConfig(inputOpts);
  if (!result) {
    return null;
  }
  const { options, context } = result;

  const optionDefaults = {};
  const passes = [[]];
  try {
    const { plugins, presets } = options;
}

우리는 우리가 사전 설정 속성 프로파일을 사용하여 플러그인을 얻을 것을 볼 수 있습니다 다음에 제공하는 모든 사전 설정 프리셋 실행 방법을 통해 플러그인 플러그인 :

"... / 인덱스"에서 문맥으로 수입 *;

const loadDescriptor = makeWeakCache(function*(
  { value, options, dirname, alias }: UnloadedDescriptor,
  cache: CacheConfigurator<SimpleContext>,
): Handler<LoadedDescriptor> {

    try {
     const api = {
      ...context,
      ...makeAPI(cache),
    };
      item = value(api, options, dirname);
    } catch (e) {
    
      throw e;
    }
  }

우리는 바벨 코어 오브젝트를 통과하는 것이 API는, 우리가 매개 변수를 전달 옵션 것으로,이 dirname은 현재 폴더 디렉터리 바벨 테스트입니다.

하자의 진보는 플러그인 PluginTest1.js (A = 10 var에 AAA = 10가 된 변수 VAR)을 작성 :

module.exports = function (api, options, dirname) {
    let t = api.types;
    console.log(options)
    console.log(dirname)
    return {
        visitor: {
            VariableDeclarator: {
                enter(path,state) {
                    console.log(path)
                    if(path.node.id.name == 'a'){
                        path.node.id.name="aaa";
                    }
                },
                exit() {
                    console.log("Exited!");
                }
            }
        }
    }
};

우리는 플러그 인 매개 변수를 우리의 제안에 대응 API를, 옵션, dirname이 있음을 우리가 볼 수있는 특정 분석 카자흐스탄 후 다시 연결 :

module.exports = function (api, options, dirname) {

글쎄, 우리가 완료 구성 파일 패키지 / 바벨 코어 / SRC / 변환 - file.js은 그 전에 내려 가서 계속 :

const transformFileRunner = gensync<[string, ?InputOptions], FileResult | null>(
	//加载配置文件
    const config: ResolvedConfig | null = yield* loadConfig(options);
    if (config === null) return null;
	//加载源文件
    const code = yield* fs.readFile(filename, "utf8");
    //开始编译
    return yield* run(config, code);
  },
);

당신이 실행 설정 직접 실행 방법 취득 후 우리는 볼 수 있습니다
패키지 / 바벨 코어 / SRC / 변환 /하는 index.js를 :

  config: ResolvedConfig,
  code: string,
  ast: ?(BabelNodeFile | BabelNodeProgram),
): Handler<FileResult> {
  const file = yield* normalizeFile(
    config.passes,
    normalizeOptions(config),
    code,
    ast,
  );

  const opts = file.opts;
  try {
    yield* transformFile(file, config.passes);
  } catch (e) {
    e.message = `${opts.filename ?? "unknown"}: ${e.message}`;
    if (!e.code) {
      e.code = "BABEL_TRANSFORM_ERROR";
    }
    throw e;
  }

  let outputCode, outputMap;
  try {
    if (opts.code !== false) {
      ({ outputCode, outputMap } = generateCode(config.passes, file));
    }
  } catch (e) {
    e.message = `${opts.filename ?? "unknown"}: ${e.message}`;
    if (!e.code) {
      e.code = "BABEL_GENERATE_ERROR";
    }
    throw e;
  }

  return {
    metadata: file.metadata,
    options: opts,
    ast: opts.ast === true ? file.ast : null,
    code: outputCode === undefined ? null : outputCode,
    map: outputMap === undefined ? null : outputMap,
    sourceType: file.ast.program.sourceType,
  };
}

코드를 좀 더하지 평방 할! 우리의 단계별

먼저 우리는 normalizeFile 방법의 구현을 참조하십시오

export function* run(
  config: ResolvedConfig,
  code: string,
  ast: ?(BabelNodeFile | BabelNodeProgram),
): Handler<FileResult> {
  const file = yield* normalizeFile(
    config.passes,
    normalizeOptions(config),
    code,
    ast,
  );

패키지 / 바벨 코어 / SRC / 변환 / 정규화-file.js :

export default function* normalizeFile(
  pluginPasses: PluginPasses,
  options: Object,
  code: string,
  ast: ?(BabelNodeFile | BabelNodeProgram),
): Handler<File> {
  code = `${code || ""}`;

  if (ast) {
    if (ast.type === "Program") {
      ast = t.file(ast, [], []);
    } else if (ast.type !== "File") {
      throw new Error("AST root must be a Program or File node");
    }
    ast = cloneDeep(ast);
  } else {
    ast = yield* parser(pluginPasses, options, code);
  }

우리가하지 AST 통과하면 당신은 파서 방법에 의해 AST (추상 구문 트리) 개체를 얻을 것이다 볼 수 있습니다.

AST 그래서 무엇인가?

컴퓨터 과학에서, AST (추상 구문 트리, AST), 또는 단순히 구문 트리 (구문 트리), 소스 코드 구문 구조의 추상 표현입니다. 이것은 트리의 형태 언어 신택스 구조를 프로그래밍 성능, 트리의 각 노드는 구조화 된 소스 코드를 나타냈다.

음, 헤비급 데뷔 파서의 바벨
파서는 파서 바벨이다. 원래 도토리 프로젝트는 밖으로 포크. 도토리는 사용하기 쉬운, 그리고 기반 아키텍처에서 플러그인 비표준 특성 (뿐만 아니라 미래의 그 표준 기능) 설계를 위해 매우 빠르고,

우리의 코드의 변환 바벨을 통해 구문 분석 후 :

/* test.js */
const fn = () => {}
new Promise(() => {})
class Test {}
const c = [1, 2, 3].includes(1)
//测试插件1
var a=10;

그것은으로 변환됩니다 :

{
  "type": "Program",
  "start": 0,
  "end": 120,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 14,
      "end": 33,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 20,
          "end": 33,
          "id": {
            "type": "Identifier",
            "start": 20,
            "end": 22,
            "name": "fn"
          },
          "init": {
            "type": "ArrowFunctionExpression",
            "start": 25,
            "end": 33,
            "id": null,
            "expression": false,
            "generator": false,
            "async": false,
            "params": [],
            "body": {
              "type": "BlockStatement",
              "start": 31,
              "end": 33,
              "body": []
            }
          }
        }
      ],
      "kind": "const"
    },
    {
      "type": "ExpressionStatement",
      "start": 34,
      "end": 55,
      "expression": {
        "type": "NewExpression",
        "start": 34,
        "end": 55,
        "callee": {
          "type": "Identifier",
          "start": 38,
          "end": 45,
          "name": "Promise"
        },
        "arguments": [
          {
            "type": "ArrowFunctionExpression",
            "start": 46,
            "end": 54,
            "id": null,
            "expression": false,
            "generator": false,
            "async": false,
            "params": [],
            "body": {
              "type": "BlockStatement",
              "start": 52,
              "end": 54,
              "body": []
            }
          }
        ]
      }
    },
    {
      "type": "ClassDeclaration",
      "start": 56,
      "end": 69,
      "id": {
        "type": "Identifier",
        "start": 62,
        "end": 66,
        "name": "Test"
      },
      "superClass": null,
      "body": {
        "type": "ClassBody",
        "start": 67,
        "end": 69,
        "body": []
      }
    },
    {
      "type": "VariableDeclaration",
      "start": 70,
      "end": 101,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 76,
          "end": 101,
          "id": {
            "type": "Identifier",
            "start": 76,
            "end": 77,
            "name": "c"
          },
          "init": {
            "type": "CallExpression",
            "start": 80,
            "end": 101,
            "callee": {
              "type": "MemberExpression",
              "start": 80,
              "end": 98,
              "object": {
                "type": "ArrayExpression",
                "start": 80,
                "end": 89,
                "elements": [
                  {
                    "type": "Literal",
                    "start": 81,
                    "end": 82,
                    "value": 1,
                    "raw": "1"
                  },
                  {
                    "type": "Literal",
                    "start": 84,
                    "end": 85,
                    "value": 2,
                    "raw": "2"
                  },
                  {
                    "type": "Literal",
                    "start": 87,
                    "end": 88,
                    "value": 3,
                    "raw": "3"
                  }
                ]
              },
              "property": {
                "type": "Identifier",
                "start": 90,
                "end": 98,
                "name": "includes"
              },
              "computed": false
            },
            "arguments": [
              {
                "type": "Literal",
                "start": 99,
                "end": 100,
                "value": 1,
                "raw": "1"
              }
            ]
          }
        }
      ],
      "kind": "const"
    },
    {
      "type": "VariableDeclaration",
      "start": 110,
      "end": 119,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 114,
          "end": 118,
          "id": {
            "type": "Identifier",
            "start": 114,
            "end": 115,
            "name": "a"
          },
          "init": {
            "type": "Literal",
            "start": 116,
            "end": 118,
            "value": 10,
            "raw": "10"
          }
        }
      ],
      "kind": "var"
    }
  ],
  "sourceType": "module"
}

작은 파트너는 직접 사용할 수 있습니다 : 컨버터 AST의 온라인 버전을

그림 삽입 설명 여기
간단한 구문 분석 방법에서 살펴 보자 :

export default function* parser(
  pluginPasses: PluginPasses,
  { parserOpts, highlightCode = true, filename = "unknown" }: Object,
  code: string,
): Handler<ParseResult> {
  try {
    const results = [];
    for (const plugins of pluginPasses) {
      for (const plugin of plugins) {
        const { parserOverride } = plugin;
        if (parserOverride) {
          const ast = parserOverride(code, parserOpts, parse);

          if (ast !== undefined) results.push(ast);
        }
      }
    }

    if (results.length === 0) {
      return parse(code, parserOpts);
    } else if (results.length === 1) {
      yield* []; // If we want to allow async parsers
      if (typeof results[0].then === "function") {
        throw new Error(
          `You appear to be using an async parser plugin, ` +
            `which your current version of Babel does not support. ` +
            `If you're using a published plugin, you may need to upgrade ` +
            `your @babel/core version.`,
        );
      }
      return results[0];
    }
    throw new Error("More than one plugin attempted to override parsing.");
  } catch (err) {
    if (err.code === "BABEL_PARSER_SOURCETYPE_MODULE_REQUIRED") {
      err.message +=
        "\nConsider renaming the file to '.mjs', or setting sourceType:module " +
        "or sourceType:unambiguous in your Babel config for this file.";
      // err.code will be changed to BABEL_PARSE_ERROR later.
    }

    const { loc, missingPlugin } = err;
    if (loc) {
      const codeFrame = codeFrameColumns(
        code,
        {
          start: {
            line: loc.line,
            column: loc.column + 1,
          },
        },
        {
          highlightCode,
        },
      );
      if (missingPlugin) {
        err.message =
          `${filename}: ` +
          generateMissingPluginMessage(missingPlugin[0], loc, codeFrame);
      } else {
        err.message = `${filename}: ${err.message}\n\n` + codeFrame;
      }
      err.code = "BABEL_PARSE_ERROR";
    }
    throw err;
  }
}

코드 또는 많은,의는 구문 분석 부분과 관련 플러그인을 언급하자 :

  for (const plugins of pluginPasses) {
      for (const plugin of plugins) {
        const { parserOverride } = plugin;
        if (parserOverride) {
          const ast = parserOverride(code, parserOpts, parse);

          if (ast !== undefined) results.push(ast);
        }
      }

그래서 우리는의 직접 parserOverride 이동 parserOverride 플러그인 우리의 결의의 바벨을 충당하기 위해 / 파서의 방법을 제공하는 플러그인이있을 때.
나는 하 중요하지 않습니다 이해하지 않는다! ! 구문 분석 특정 사용 우리는 해상도 뒤에 넣어.

간단한 독서 구문 분석 후, 우리는 방법을 계속 실행
패키지를 / 바벨 코어 / SRC / 변환 /하는 index.js :

export function* run(
  config: ResolvedConfig,
  code: string,
  ast: ?(BabelNodeFile | BabelNodeProgram),
): Handler<FileResult> {
	//获取ast对象
  const file = yield* normalizeFile();

  const opts = file.opts;
  try {
  	//执行转换操作
    yield* transformFile(file, config.passes);
  } catch (e) {
  }

우리는 transformFile 방법을 계속 볼 수 있으며, 우리는 AST 통과 transformFile 방법을 객체 :

function* transformFile(file: File, pluginPasses: PluginPasses): Handler<void> {
  for (const pluginPairs of pluginPasses) {
    const passPairs = [];
    const passes = [];
    const visitors = [];

    for (const plugin of pluginPairs.concat([loadBlockHoistPlugin()])) {
      const pass = new PluginPass(file, plugin.key, plugin.options);

      passPairs.push([plugin, pass]);
      passes.push(pass);
      visitors.push(plugin.visitor);
    }

    for (const [plugin, pass] of passPairs) {
      const fn = plugin.pre;
      if (fn) {
        const result = fn.call(pass, file);

        yield* [];
        if (isThenable(result)) {
          throw new Error(
            `You appear to be using an plugin with an async .pre, ` +
              `which your current version of Babel does not support. ` +
              `If you're using a published plugin, you may need to upgrade ` +
              `your @babel/core version.`,
          );
        }
      }
    }

    // merge all plugin visitors into a single visitor
    const visitor = traverse.visitors.merge(
      visitors,
      passes,
      file.opts.wrapPluginVisitorMethod,
    );
    traverse(file.ast, visitor, file.scope);

    for (const [plugin, pass] of passPairs) {
      const fn = plugin.post;
      if (fn) {
        const result = fn.call(pass, file);

        yield* [];
        if (isThenable(result)) {
          throw new Error(
            `You appear to be using an plugin with an async .post, ` +
              `which your current version of Babel does not support. ` +
              `If you're using a published plugin, you may need to upgrade ` +
              `your @babel/core version.`,
          );
        }
      }
    }
  }
}

또는 문구 "음주 우리는 단계별로 보면! 정사각형되지는"첫째, 우리는 다음을 참조하십시오

//遍历所有的插件,获取插件的visitor属性,然后传给visitors
 for (const plugin of pluginPairs.concat([loadBlockHoistPlugin()])) {
      const pass = new PluginPass(file, plugin.key, plugin.options);

      passPairs.push([plugin, pass]);
      passes.push(pass);
      visitors.push(plugin.visitor);
    }

그래서 어떤 방문자입니까? 우리가 있음을 볼 수 있습니다 전에 사용자 정의 플러그인 PluginTest1.js을 언급 :

module.exports = function (api, options, dirname) {
    let t = api.types;
    console.log(options)
    console.log(dirname)
    return {
        visitor: {
            VariableDeclarator: {
                enter(path,state) {
                    console.log(path)
                    if(path.node.id.name == 'a'){
                        path.node.id.name="aaa";
                    }
                },
                exit() {
                    console.log("Exited!");
                }
            }
        }
    }
};

사전에 대한 첫 번째 이야기, 사후 방문자, 트래버스는 추상 구문 트리 AST 객체에 대한 액세스를 제공 할 수 있도록하는

다음 단계는 다른 헤비급 이송 데뷔의 바벨 그래서
바벨 트래버스 (이송) 모듈을 제거하고 노드를 추가, 전체 나무의 상태를 유지하고, 교체 할 책임이 있습니다.

실행 방법으로 돌아가려면
패키지 / 바벨 코어 / SRC / 변환 /하는 index.js :

export function* run(
  config: ResolvedConfig,
  code: string,
  ast: ?(BabelNodeFile | BabelNodeProgram),
): Handler<FileResult> {
 //获取ast对象(parser)
  const file = yield* normalizeFile();
  try {
  //(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点。
    yield* transformFile(file, config.passes);
  } catch (e) {
   
  }
({ outputCode, outputMap } = generateCode(config.passes, file));
 

可以看到执行了generateCode方法,这时babel的最后一个重量级选手babel-generator登场了

Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射(sourcemaps)。

最后run方法返回generator生成的代码:

return {
    metadata: file.metadata,
    options: opts,
    ast: opts.ast === true ? file.ast : null,
    code: outputCode === undefined ? null : outputCode,
    map: outputMap === undefined ? null : outputMap,
    sourceType: file.ast.program.sourceType,
  };

整个babel-cli到babel-core的过程随着我们的demo跟我们的源码就讲完了。

我们重新整理一下整个过程:

  1. babel-cli开始读取我们的参数(源文件test1.js、输出文件test1.babel.js、配置文件.babelrc)
  2. babel-core根据babel-cli的参数开始编译
  3. Babel Parser 把我们传入的源码解析成ast对象
  4. Babel Traverse(遍历)模块维护了整棵树的状态,并且负责替换、移除和添加节点(也就是结合我们传入的插件把es6转换成es5的一个过程)
  5. Babel Generator模块是 Babel 的代码生成器,它读取AST并将其转换为代码和源码映射(sourcemaps)。

好啦,到此我们算是把babel的整个过程简单的跑了一下,为了加深对每个流程的理解,我们不经过babel-core跟babel-cli单独去用一下parser、traverse、generator。

//我们的es6源码
const code = `
    const result=a*b;
    const result1=()=>{};
`;
const {parse}=require("@babel/parser");
const traverse =require("@babel/traverse").default;
const t = require("babel-types");
const generator = require("@babel/generator").default;

//把es6源码通过parser转换成ast对象
const ats=parse(code,{
    sourceType: "module"
});
//把ast对象通过traverse转换成es5代码
traverse(ats,{
    enter(path) {
        if (t.isIdentifier(path.node, { name: "a" })) {
          path.node.name = "aa";
        }
        if (path.isArrowFunctionExpression()){ //es6转换成es5
            path.arrowFunctionToExpression({
                // While other utils may be fine inserting other arrows to make more transforms possible,
                // the arrow transform itself absolutely cannot insert new arrow functions.
                allowInsertArrow: false,
                specCompliant: false,
              });
        }
    }
});
//通过generator转换ast最后输出es5代码
console.log(generator(ats));

我们运行一下代码:

$ node ./babel-test/demo/demo1.js 

结果输出:

{ 
  code: 'const result = aa * b;\n\nconst result1 = function () {};',
  map: null,
  rawMappings: null 
}

可以看到,最终我们实现了把es6的箭头函数转换成es5的过程。

代码中我们可以看到:

//把ast对象通过traverse转换成es5代码
traverse(ats,{
    enter(path) {
        if (t.isIdentifier(path.node, { name: "a" })) {
          path.node.name = "aa";
        }
        if (path.isArrowFunctionExpression()){ //es6转换成es5
            path.arrowFunctionToExpression({
                // While other utils may be fine inserting other arrows to make more transforms possible,
                // the arrow transform itself absolutely cannot insert new arrow functions.
                allowInsertArrow: false,
                specCompliant: false,
              });
        }
    }
});

我们打开一个官方的插件babel-plugin-transform-arrow-functions:

import { declare } from "@babel/helper-plugin-utils";
import type NodePath from "@babel/traverse";

export default declare((api, options) => {
  api.assertVersion(7);

  const { spec } = options;
  return {
    name: "transform-arrow-functions",

    visitor: {
      ArrowFunctionExpression(
        path: NodePath<BabelNodeArrowFunctionExpression>,
      ) {
        // In some conversion cases, it may have already been converted to a function while this callback
        // was queued up.
        if (!path.isArrowFunctionExpression()) return;

        path.arrowFunctionToExpression({
          // While other utils may be fine inserting other arrows to make more transforms possible,
          // the arrow transform itself absolutely cannot insert new arrow functions.
          allowInsertArrow: false,
          specCompliant: !!spec,
        });
      },
    },
  };
});

哈哈!! 是不是很简单呢? 其实babel也就是把很多的一些插件组合起来最终实现代码的转换,好啦~ 接下来我们就围绕babel的一些常用的插件做解析了

未完待续~~

欢迎志同道合的小伙伴一起学习、一起进步

欢迎入群~~~~~~~

参考:

https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md#toc-check-if-a-node-is-a-certain-type

게시 된 128 개 원래 기사 · 원 찬양 113 · 전망 340 000 +

추천

출처blog.csdn.net/vv_bug/article/details/103823257