From d53e8451d2cddc24b361492f29b9269141de76b8 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 20 Dec 2022 16:42:12 +0800 Subject: [PATCH 1/4] Use acorn to postprocess Astro globs --- .changeset/five-cups-battle.md | 5 ++ .../fixtures/pass-js/src/components/React.tsx | 4 +- .../fixtures/pass-js/src/pages/index.astro | 3 +- packages/astro/e2e/pass-js.test.js | 3 +- packages/astro/package.json | 2 + .../vite-plugin-astro-postprocess/index.ts | 75 +++++++------------ pnpm-lock.yaml | 4 + 7 files changed, 42 insertions(+), 54 deletions(-) create mode 100644 .changeset/five-cups-battle.md diff --git a/.changeset/five-cups-battle.md b/.changeset/five-cups-battle.md new file mode 100644 index 000000000000..f4a92050a3f4 --- /dev/null +++ b/.changeset/five-cups-battle.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Use acorn to postprocess Astro globs diff --git a/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx index 169e1a61f4c7..02023fc9d61e 100644 --- a/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx +++ b/packages/astro/e2e/fixtures/pass-js/src/components/React.tsx @@ -3,9 +3,7 @@ import { useState } from 'react'; interface Props { obj: BigNestedObject; - // TODO: support BigInt in `astro:postprocess` - // num: bigint; - num: number; + num: bigint; arr: any[]; map: Map; set: Set; diff --git a/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro index 830fb9c87692..be40948d82d7 100644 --- a/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro +++ b/packages/astro/e2e/fixtures/pass-js/src/pages/index.astro @@ -30,8 +30,7 @@ set.add('test2');
- - +
diff --git a/packages/astro/e2e/pass-js.test.js b/packages/astro/e2e/pass-js.test.js index 741c8880056f..503f8274bfa3 100644 --- a/packages/astro/e2e/pass-js.test.js +++ b/packages/astro/e2e/pass-js.test.js @@ -32,8 +32,7 @@ test.describe('Passing JS into client components', () => { await expect(regExpValue).toHaveText('ok'); }); - // TODO: support BigInt in `astro:postprocess` - test.skip('BigInts', async ({ page }) => { + test('BigInts', async ({ page }) => { await page.goto('/'); const bigIntType = await page.locator('#bigint-type'); diff --git a/packages/astro/package.json b/packages/astro/package.json index de9043482488..89ae0e62d948 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -124,6 +124,7 @@ "@types/babel__core": "^7.1.19", "@types/html-escaper": "^3.0.0", "@types/yargs-parser": "^21.0.0", + "acorn": "^8.8.1", "boxen": "^6.2.1", "ci-info": "^3.3.1", "common-ancestor-path": "^1.0.1", @@ -133,6 +134,7 @@ "devalue": "^4.2.0", "diff": "^5.1.0", "es-module-lexer": "^1.1.0", + "estree-walker": "^3.0.1", "execa": "^6.1.0", "fast-glob": "^3.2.11", "github-slugger": "^1.4.0", diff --git a/packages/astro/src/vite-plugin-astro-postprocess/index.ts b/packages/astro/src/vite-plugin-astro-postprocess/index.ts index c140ad72e395..00ceb49177ef 100644 --- a/packages/astro/src/vite-plugin-astro-postprocess/index.ts +++ b/packages/astro/src/vite-plugin-astro-postprocess/index.ts @@ -1,7 +1,6 @@ -import { parse as babelParser } from '@babel/parser'; -import type { ArrowFunctionExpressionKind, CallExpressionKind } from 'ast-types/gen/kinds'; -import type { NodePath } from 'ast-types/lib/node-path'; -import { parse, print, types, visit } from 'recast'; +import { parse } from 'acorn'; +import { walk } from 'estree-walker'; +import MagicString from 'magic-string'; import type { Plugin } from 'vite'; import type { AstroSettings } from '../@types/astro'; import { isMarkdownFile } from '../core/util.js'; @@ -28,57 +27,39 @@ export default function astro(_opts: AstroPluginOptions): Plugin { return null; } + let s: MagicString | undefined; const ast = parse(code, { - // We need to use the babel parser because `import.meta.hot` is not - // supported by esprima (default parser). In the future, we should - // experiment with other parsers if Babel is too slow or heavy. - parser: { parse: babelParser }, + ecmaVersion: 'latest', + sourceType: 'module', }); - - visit(ast, { - visitCallExpression: function (path) { - // Filter out anything that isn't `Astro.glob()` or `Astro2.glob()` + walk(ast, { + enter(node: any) { + // Transform `Astro.glob("./pages/*.astro")` to `Astro.glob(import.meta.glob("./pages/*.astro"), () => "./pages/*.astro")` + // Also handle for `Astro2.glob()` if ( - !types.namedTypes.MemberExpression.check(path.node.callee) || - !types.namedTypes.Identifier.check(path.node.callee.property) || - !(path.node.callee.property.name === 'glob') || - !types.namedTypes.Identifier.check(path.node.callee.object) || - !(path.node.callee.object.name === 'Astro' || path.node.callee.object.name === 'Astro2') + node.type === 'CallExpression' && + node.callee.type === 'MemberExpression' && + node.callee.property.name === 'glob' && + (node.callee.object.name === 'Astro' || node.callee.object.name === 'Astro2') && + node.arguments.length ) { - this.traverse(path); - return; + const rawArgs = node.arguments[0].raw; + s ??= new MagicString(code); + s.overwrite( + node.arguments[0].start, + node.arguments[node.arguments.length - 1].end, + `import.meta.glob(${rawArgs}), () => ${rawArgs}` + ); } - - // Wrap the `Astro.glob()` argument with `import.meta.glob`. - const argsPath = path.get('arguments', 0) as NodePath; - const args = argsPath.value; - argsPath.replace( - { - type: 'CallExpression', - callee: { - type: 'MemberExpression', - object: { - type: 'MetaProperty', - meta: { type: 'Identifier', name: 'import' }, - property: { type: 'Identifier', name: 'meta' }, - }, - property: { type: 'Identifier', name: 'glob' }, - computed: false, - }, - arguments: [args], - } as CallExpressionKind, - { - type: 'ArrowFunctionExpression', - body: args, - params: [], - } as ArrowFunctionExpressionKind - ); - return false; }, }); - const result = print(ast); - return { code: result.code, map: result.map }; + if (s) { + return { + code: s.toString(), + map: s.generateMap(), + }; + } }, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d391b5cf6d6b..af998faf473d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -422,6 +422,7 @@ importers: '@types/send': ^0.17.1 '@types/unist': ^2.0.6 '@types/yargs-parser': ^21.0.0 + acorn: ^8.8.1 ast-types: ^0.14.2 astro-scripts: workspace:* boxen: ^6.2.1 @@ -436,6 +437,7 @@ importers: diff: ^5.1.0 eol: ^0.9.1 es-module-lexer: ^1.1.0 + estree-walker: ^3.0.1 execa: ^6.1.0 fast-glob: ^3.2.11 github-slugger: ^1.4.0 @@ -500,6 +502,7 @@ importers: '@types/babel__core': 7.1.20 '@types/html-escaper': 3.0.0 '@types/yargs-parser': 21.0.0 + acorn: 8.8.1 boxen: 6.2.1 ci-info: 3.6.1 common-ancestor-path: 1.0.1 @@ -509,6 +512,7 @@ importers: devalue: 4.2.0 diff: 5.1.0 es-module-lexer: 1.1.0 + estree-walker: 3.0.1 execa: 6.1.0 fast-glob: 3.2.12 github-slugger: 1.5.0 From 39abd14a0270b035d3436203801df33ad5a4c1d0 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 20 Dec 2022 16:45:54 +0800 Subject: [PATCH 2/4] Remove unused dep --- packages/astro/package.json | 1 - pnpm-lock.yaml | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/astro/package.json b/packages/astro/package.json index 89ae0e62d948..070ef94dd75a 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -194,7 +194,6 @@ "@types/rimraf": "^3.0.2", "@types/send": "^0.17.1", "@types/unist": "^2.0.6", - "ast-types": "^0.14.2", "astro-scripts": "workspace:*", "chai": "^4.3.6", "cheerio": "^1.0.0-rc.11", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af998faf473d..ccfc9bbe1fae 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -423,7 +423,6 @@ importers: '@types/unist': ^2.0.6 '@types/yargs-parser': ^21.0.0 acorn: ^8.8.1 - ast-types: ^0.14.2 astro-scripts: workspace:* boxen: ^6.2.1 chai: ^4.3.6 @@ -571,7 +570,6 @@ importers: '@types/rimraf': 3.0.2 '@types/send': 0.17.1 '@types/unist': 2.0.6 - ast-types: 0.14.2 astro-scripts: link:../../scripts chai: 4.3.7 cheerio: 1.0.0-rc.12 @@ -10705,6 +10703,7 @@ packages: engines: {node: '>=4'} dependencies: tslib: 2.4.1 + dev: false /astring/1.8.3: resolution: {integrity: sha512-sRpyiNrx2dEYIMmUXprS8nlpRg2Drs8m9ElX9vVEXaCB4XEAJhKfs7IcX0IwShjuOAjLR6wzIrgoptz1n19i1A==} From 8798c750b98dfa91142f0ed9e58ebd7d77ed0eff Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 20 Dec 2022 17:14:14 +0800 Subject: [PATCH 3/4] Fix literal compat --- packages/astro/src/vite-plugin-astro-postprocess/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/astro/src/vite-plugin-astro-postprocess/index.ts b/packages/astro/src/vite-plugin-astro-postprocess/index.ts index 00ceb49177ef..b9f5b5421ef1 100644 --- a/packages/astro/src/vite-plugin-astro-postprocess/index.ts +++ b/packages/astro/src/vite-plugin-astro-postprocess/index.ts @@ -43,7 +43,13 @@ export default function astro(_opts: AstroPluginOptions): Plugin { (node.callee.object.name === 'Astro' || node.callee.object.name === 'Astro2') && node.arguments.length ) { - const rawArgs = node.arguments[0].raw; + let rawArgs: string = node.arguments[0].raw; + // If argument is template literal, try convert to a normal string. + // This is needed for compat with previous recast strategy. + // TODO: Remove in Astro 2.0 + if (rawArgs.startsWith('`') && rawArgs.endsWith('`') && !rawArgs.includes('${')) { + rawArgs = JSON.stringify(rawArgs.slice(1, -1)); + } s ??= new MagicString(code); s.overwrite( node.arguments[0].start, From 9981f0e200ccfb87b67fb6adb9d9c25439e3c3a0 Mon Sep 17 00:00:00 2001 From: bluwy Date: Tue, 20 Dec 2022 20:38:01 +0800 Subject: [PATCH 4/4] Fix literal again --- .../src/vite-plugin-astro-postprocess/index.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/astro/src/vite-plugin-astro-postprocess/index.ts b/packages/astro/src/vite-plugin-astro-postprocess/index.ts index b9f5b5421ef1..435457a5d56a 100644 --- a/packages/astro/src/vite-plugin-astro-postprocess/index.ts +++ b/packages/astro/src/vite-plugin-astro-postprocess/index.ts @@ -43,18 +43,21 @@ export default function astro(_opts: AstroPluginOptions): Plugin { (node.callee.object.name === 'Astro' || node.callee.object.name === 'Astro2') && node.arguments.length ) { - let rawArgs: string = node.arguments[0].raw; + const firstArgStart = node.arguments[0].start; + const firstArgEnd = node.arguments[0].end; + const lastArgEnd = node.arguments[node.arguments.length - 1].end; + let firstArg = code.slice(firstArgStart, firstArgEnd); // If argument is template literal, try convert to a normal string. // This is needed for compat with previous recast strategy. // TODO: Remove in Astro 2.0 - if (rawArgs.startsWith('`') && rawArgs.endsWith('`') && !rawArgs.includes('${')) { - rawArgs = JSON.stringify(rawArgs.slice(1, -1)); + if (firstArg.startsWith('`') && firstArg.endsWith('`') && !firstArg.includes('${')) { + firstArg = JSON.stringify(firstArg.slice(1, -1)); } s ??= new MagicString(code); s.overwrite( - node.arguments[0].start, - node.arguments[node.arguments.length - 1].end, - `import.meta.glob(${rawArgs}), () => ${rawArgs}` + firstArgStart, + lastArgEnd, + `import.meta.glob(${firstArg}), () => ${firstArg}` ); } },