We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
前段时间,写了一个 webpack-loader,auto-inject-async-catch-loader,晚上 8 点多发的 npm 包。昨天早上,上 npm 官网一看,才十几个小时下载量 282 次(着实有点意外😯)~
在之前,我写过一篇文章《现场教学,优雅地处理基于 Vue CLI 项目中的 async await 异常》介绍了如何在 Vue CLI 中给代码自动加 try catch,当时在文中也讲了这种做法欠妥。所以,上周末我花了一些时间,重新整理了一下如何使用 babel 的 tool 基于抽象语法树 AST 来实现对 Vue CLI 项目代码自动注入 try catch。
try catch
auto-inject-async-catch-loader 是一个 webpack-loader,基于 babel 提供的 tool 来通过遍历抽象语法树 AST 来实现对 AwaitExpression AST 节点添加 TryStatement AST 节点,从而完成对 async function自动注入 try catch 的机制。auto-inject-async-catch-loader 的工作机制如下图所示:
AwaitExpression
TryStatement
async function
而 auto-inject-async-catch-loader 这个 loader 是 fork 的 async-catch-loader。所以,这里给上作者一个大大的 Respect 👍。起初,我是想着提个 PR,没必要反复造轮子,但是出于时间问题,就 fork 了一份改了改。
相比较 async-catch-loader ,auto-inject-async-catch-loader 做了以下两点优化:
1.优化了向上查找 parent 的过程,优化后的 traverse 如下所示:
traverse
traverse(ast, { AwaitExpression(path) { // 已经包含 try 语句则直接退出 if ( path.findParent(path => t.isTryStatement(path.node)) ) { return; } // 查找最外层的 async 语句 const blockParent = path.findParent(path => t.isBlockStatement(path.node) && isAsyncFuncNode(path.parentPath.node)) const tryCatchAst = t.tryStatement( blockParent.node, t.catchClause( t.identifier(options.identifier), t.blockStatement(catchNode) ), finallyNode && t.blockStatement(finallyNode) ) blockParent.replaceWithMultiple([tryCatchAst]) } });
2.支持使用 TypeScript + Vue CLI 开发的情况。此时 Vue 组件是 Class 语法,例如:
<template></template> <script lang="ts"> import { Vue, Component } from "@vue-property-decorator" @Component export default class Login extends Vue { private async created(): Promise<any> { await Promise.resolve("user login") } } </script>
可以看到 created(async function)是写在 Class 内部的,即其对应的抽象语法树 AST 的 type 为 ClassMethod,所以在 isAsyncFunction 判断函数中增加加了对 ClassMethod 的判断:
created
ClassMethod
isAsyncFunction
const isAsyncFuncNode = node => t.isFunctionDeclaration(node, { async: true }) || t.isArrowFunctionExpression(node, { async: true }) || t.isFunctionExpression(node, { async: true }) || t.isObjectMethod(node, { async: true }) || t.isClassMethod(node, { async: true });
相信很多同学对于配置 Vue CLI 的 Webpack 一头雾水,这里我就顺带地给大家的讲解一下如何在 Vue CLI 中使用 auto-inject-async-catch-loader。
首先,当然是安装 auto-inject-async-catch-loader 依赖:
npm i auto-inject-async-catch-loader -D
然后,配置 Webpack。而通常情况下,使用 Vue CLI 开发的同学会分为两类:
1.使用 JavaScript 开发
使用 JavaScirpt 开发的同学只需要通过 chainwebpack 选项在 js rule 中添加一个 loader 就行。在 vue.config.js 的 chainWepack 中加入如下配置:
chainwebpack
js
loader
chainWepack
chainWepack: (config) => { const jsRule = config.module.rule("js"); jsRule .use("auto-inject-async-catch-loader") .loader("auto-inject-async-catch-loader") .end() }
2.使用 TypeScript 开发
使用 TypeScript 开发的同学则需要重写整个 ts rule 的 loader 配置。在 vue.config.ts 的 chainWepack 选项中加入如下配置:
ts
chainWebpack: (config) => { const tsRule = config.module.rule("ts"); tsRule.uses.clear(); tsRule .use("cache-loader") .loader("cache-loader") .end() .use("babel-loader") .loader("babel-loader") .end() .use("auto-inject-async-catch-loader") .loader("auto-inject-async-catch-loader") .tap(() => { return { catchCode: 'console.error(e)' } }) .end() .use("ts-loader") .loader("ts-loader") .tap(() => { return { transpileOnly: true, appendTsSuffixTo: [ '\\.vue$' ], happyPackMode: false } }) .end() }
至于为什么需要重写整个 ts 对应的 rule,因为此时项目中代码的 loader 的加载顺序是 ts-loader 到 babel-loader 再到 cache-loader,auto-inject-async-catch-loader 必须要在 babel-loader 之前、ts-loader 之后加载:
而 Vue CLI 的 Webpack 配置是使用 webpack-chain 生成的,但是 webapck-chain 并没有提供在某个 loader 后插入 loader 的方法(只对 plugin 支持 before 和 after 方法)。所以,这里我们需要重写整个 ts rule,保证 ts-loader 到 auto-inject-async-catch-loader 到 babel-loader 再到 caceh-loader 的加载顺序:
最后讲讲后期计划,写一个 babel-plugin 实现同样的功能,用 babel-plugin 实现则会精简地多,因为 babeld-plugin 本身提供了一些变量供于使用,例如可以使用 visitor 遍历抽象语法树 AST。当然,欢迎各位同学使用 auto-inject-async-catch-loader,如果有其他需求也可以给我提 Issue,或者微信(wu1957503379)联系我。
visitor
https:/yeyan1996/async-catch-loader
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
前段时间,写了一个 webpack-loader,auto-inject-async-catch-loader,晚上 8 点多发的 npm 包。昨天早上,上 npm 官网一看,才十几个小时下载量 282 次(着实有点意外😯)~
在之前,我写过一篇文章《现场教学,优雅地处理基于 Vue CLI 项目中的 async await 异常》介绍了如何在 Vue CLI 中给代码自动加
try catch
,当时在文中也讲了这种做法欠妥。所以,上周末我花了一些时间,重新整理了一下如何使用 babel 的 tool 基于抽象语法树 AST 来实现对 Vue CLI 项目代码自动注入try catch
。一、 auto-inject-try-catch-loader 简介
auto-inject-async-catch-loader 是一个 webpack-loader,基于 babel 提供的 tool 来通过遍历抽象语法树 AST 来实现对
AwaitExpression
AST 节点添加TryStatement
AST 节点,从而完成对async function
自动注入try catch
的机制。auto-inject-async-catch-loader 的工作机制如下图所示:而 auto-inject-async-catch-loader 这个 loader 是 fork 的 async-catch-loader。所以,这里给上作者一个大大的 Respect 👍。起初,我是想着提个 PR,没必要反复造轮子,但是出于时间问题,就 fork 了一份改了改。
相比较 async-catch-loader ,auto-inject-async-catch-loader 做了以下两点优化:
1.优化了向上查找 parent 的过程,优化后的
traverse
如下所示:2.支持使用 TypeScript + Vue CLI 开发的情况。此时 Vue 组件是 Class 语法,例如:
可以看到
created
(async function
)是写在 Class 内部的,即其对应的抽象语法树 AST 的 type 为ClassMethod
,所以在isAsyncFunction
判断函数中增加加了对ClassMethod
的判断:二、auto-inject-async-catch-loader 在 Vue CLI 中使用
相信很多同学对于配置 Vue CLI 的 Webpack 一头雾水,这里我就顺带地给大家的讲解一下如何在 Vue CLI 中使用 auto-inject-async-catch-loader。
首先,当然是安装 auto-inject-async-catch-loader 依赖:
然后,配置 Webpack。而通常情况下,使用 Vue CLI 开发的同学会分为两类:
1.使用 JavaScript 开发
使用 JavaScirpt 开发的同学只需要通过
chainwebpack
选项在js
rule 中添加一个loader
就行。在 vue.config.js 的chainWepack
中加入如下配置:2.使用 TypeScript 开发
使用 TypeScript 开发的同学则需要重写整个
ts
rule 的 loader 配置。在 vue.config.ts 的chainWepack
选项中加入如下配置:至于为什么需要重写整个
ts
对应的 rule,因为此时项目中代码的 loader 的加载顺序是 ts-loader 到 babel-loader 再到 cache-loader,auto-inject-async-catch-loader 必须要在 babel-loader 之前、ts-loader 之后加载:而 Vue CLI 的 Webpack 配置是使用 webpack-chain 生成的,但是 webapck-chain 并没有提供在某个 loader 后插入 loader 的方法(只对 plugin 支持 before 和 after 方法)。所以,这里我们需要重写整个 ts rule,保证 ts-loader 到 auto-inject-async-catch-loader 到 babel-loader 再到 caceh-loader 的加载顺序:
结语
最后讲讲后期计划,写一个 babel-plugin 实现同样的功能,用 babel-plugin 实现则会精简地多,因为 babeld-plugin 本身提供了一些变量供于使用,例如可以使用
visitor
遍历抽象语法树 AST。当然,欢迎各位同学使用 auto-inject-async-catch-loader,如果有其他需求也可以给我提 Issue,或者微信(wu1957503379)联系我。参考
https:/yeyan1996/async-catch-loader
The text was updated successfully, but these errors were encountered: