fix(nuxt): use esbuild/acorn instead of typescript dep (#21729)

This commit is contained in:
Daniel Roe 2023-06-24 00:01:17 +01:00 committed by GitHub
parent 1ee704c184
commit 789c8bfa95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 45 additions and 59 deletions

View File

@ -58,16 +58,17 @@
"@nuxt/telemetry": "^2.2.0", "@nuxt/telemetry": "^2.2.0",
"@nuxt/ui-templates": "^1.2.0", "@nuxt/ui-templates": "^1.2.0",
"@nuxt/vite-builder": "workspace:../vite", "@nuxt/vite-builder": "workspace:../vite",
"@typescript-eslint/typescript-estree": "^5.60.0",
"@unhead/ssr": "^1.1.27", "@unhead/ssr": "^1.1.27",
"@unhead/vue": "^1.1.27", "@unhead/vue": "^1.1.27",
"@vue/shared": "^3.3.4", "@vue/shared": "^3.3.4",
"acorn": "8.9.0",
"c12": "^1.4.2", "c12": "^1.4.2",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"cookie-es": "^1.0.0", "cookie-es": "^1.0.0",
"defu": "^6.1.2", "defu": "^6.1.2",
"destr": "^2.0.0", "destr": "^2.0.0",
"devalue": "^4.3.2", "devalue": "^4.3.2",
"esbuild": "^0.18.6",
"escape-string-regexp": "^5.0.0", "escape-string-regexp": "^5.0.0",
"estree-walker": "^3.0.3", "estree-walker": "^3.0.3",
"fs-extra": "^11.1.1", "fs-extra": "^11.1.1",
@ -110,7 +111,6 @@
"@types/fs-extra": "11.0.1", "@types/fs-extra": "11.0.1",
"@types/prompts": "2.4.4", "@types/prompts": "2.4.4",
"@vitejs/plugin-vue": "4.2.3", "@vitejs/plugin-vue": "4.2.3",
"acorn": "8.9.0",
"unbuild": "latest", "unbuild": "latest",
"vite": "4.3.9", "vite": "4.3.9",
"vitest": "0.32.2" "vitest": "0.32.2"

View File

@ -157,7 +157,7 @@ export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
try { try {
const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src] : await fsp.readFile(plugin.src!, 'utf-8') const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src] : await fsp.readFile(plugin.src!, 'utf-8')
_plugins.push({ _plugins.push({
...extractMetadata(code), ...await extractMetadata(code),
...plugin ...plugin
}) })
} catch (e) { } catch (e) {

View File

@ -1,7 +1,8 @@
import type { CallExpression, Property, SpreadElement } from 'estree' import type { CallExpression, Property, SpreadElement } from 'estree'
import type { Node } from 'estree-walker' import type { Node } from 'estree-walker'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import { parse } from '@typescript-eslint/typescript-estree' import { transform } from 'esbuild'
import { parse } from 'acorn'
import { defu } from 'defu' import { defu } from 'defu'
import { findExports } from 'mlly' import { findExports } from 'mlly'
import type { Nuxt } from '@nuxt/schema' import type { Nuxt } from '@nuxt/schema'
@ -40,12 +41,16 @@ export const orderMap: Record<NonNullable<ObjectPlugin['enforce']>, number> = {
} }
const metaCache: Record<string, Omit<PluginMeta, 'enforce'>> = {} const metaCache: Record<string, Omit<PluginMeta, 'enforce'>> = {}
export function extractMetadata (code: string) { export async function extractMetadata (code: string) {
let meta: PluginMeta = {} let meta: PluginMeta = {}
if (metaCache[code]) { if (metaCache[code]) {
return metaCache[code] return metaCache[code]
} }
walk(parse(code) as Node, { const js = await transform(code, { loader: 'ts' })
walk(parse(js.code, {
sourceType: 'module',
ecmaVersion: 'latest'
}) as Node, {
enter (_node) { enter (_node) {
if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return } if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return }
const node = _node as CallExpression & { start: number, end: number } const node = _node as CallExpression & { start: number, end: number }
@ -108,7 +113,6 @@ function extractMetaFromObject (properties: Array<Property | SpreadElement>) {
export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => { export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
return { return {
name: 'nuxt:remove-plugin-metadata', name: 'nuxt:remove-plugin-metadata',
enforce: 'pre',
transform (code, id) { transform (code, id) {
id = normalize(id) id = normalize(id)
const plugin = nuxt.apps.default.plugins.find(p => p.src === id) const plugin = nuxt.apps.default.plugins.find(p => p.src === id)
@ -129,7 +133,10 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
let wrapped = false let wrapped = false
try { try {
walk(parse(code, { range: true }) as Node, { walk(this.parse(code, {
sourceType: 'module',
ecmaVersion: 'latest'
}) as Node, {
enter (_node) { enter (_node) {
if (_node.type === 'ExportDefaultDeclaration' && (_node.declaration.type === 'FunctionDeclaration' || _node.declaration.type === 'ArrowFunctionExpression')) { if (_node.type === 'ExportDefaultDeclaration' && (_node.declaration.type === 'FunctionDeclaration' || _node.declaration.type === 'ArrowFunctionExpression')) {
if ('params' in _node.declaration && _node.declaration.params.length > 1) { if ('params' in _node.declaration && _node.declaration.params.length > 1) {
@ -156,14 +163,21 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
// Remove metadata that already has been extracted // Remove metadata that already has been extracted
if (!('order' in plugin) && !('name' in plugin)) { return } if (!('order' in plugin) && !('name' in plugin)) { return }
for (const [argIndex, arg] of node.arguments.entries()) { for (const [argIndex, _arg] of node.arguments.entries()) {
if (arg.type !== 'ObjectExpression') { continue } if (_arg.type !== 'ObjectExpression') { continue }
for (const [propertyIndex, property] of arg.properties.entries()) {
if (property.type === 'SpreadElement' || !('name' in property.key)) { continue } const arg = _arg as typeof _arg & { start: number, end: number }
const propertyKey = property.key.name for (const [propertyIndex, _property] of arg.properties.entries()) {
if (_property.type === 'SpreadElement' || !('name' in _property.key)) { continue }
const property = _property as typeof _property & { start: number, end: number }
const propertyKey = _property.key.name
if (propertyKey === 'order' || propertyKey === 'enforce' || propertyKey === 'name') { if (propertyKey === 'order' || propertyKey === 'enforce' || propertyKey === 'name') {
const nextIndex = arg.properties[propertyIndex + 1]?.range?.[0] || node.arguments[argIndex + 1]?.range?.[0] || (arg.range![1] - 1) const _nextNode = arg.properties[propertyIndex + 1] || node.arguments[argIndex + 1]
s.remove(property.range![0], nextIndex) const nextNode = _nextNode as typeof _nextNode & { start: number, end: number }
const nextIndex = nextNode?.start || (arg.end - 1)
s.remove(property.start, nextIndex)
} }
} }
} }

View File

@ -1,9 +1,10 @@
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import { parse } from 'acorn'
import { RemovePluginMetadataPlugin, extractMetadata } from '../src/core/plugins/plugin-metadata' import { RemovePluginMetadataPlugin, extractMetadata } from '../src/core/plugins/plugin-metadata'
describe('plugin-metadata', () => { describe('plugin-metadata', () => {
it('should extract metadata from object-syntax plugins', () => { it('should extract metadata from object-syntax plugins', async () => {
const properties = Object.entries({ const properties = Object.entries({
name: 'test', name: 'test',
enforce: 'post', enforce: 'post',
@ -15,7 +16,7 @@ describe('plugin-metadata', () => {
for (const item of properties) { for (const item of properties) {
const obj = [...properties.filter(([key]) => key !== item[0]), item] const obj = [...properties.filter(([key]) => key !== item[0]), item]
const meta = extractMetadata([ const meta = await extractMetadata([
'export default defineNuxtPlugin({', 'export default defineNuxtPlugin({',
...obj.map(([key, value]) => `${key}: ${typeof value === 'function' ? value.toString() : JSON.stringify(value)},`), ...obj.map(([key, value]) => `${key}: ${typeof value === 'function' ? value.toString() : JSON.stringify(value)},`),
'})' '})'
@ -41,7 +42,7 @@ describe('plugin-metadata', () => {
'export default function (ctx, inject) {}' 'export default function (ctx, inject) {}'
] ]
for (const plugin of invalidPlugins) { for (const plugin of invalidPlugins) {
expect(transformPlugin.transform(plugin, 'my-plugin.mjs').code).toBe('export default () => {}') expect(transformPlugin.transform.call({ parse }, plugin, 'my-plugin.mjs').code).toBe('export default () => {}')
} }
}) })
@ -53,7 +54,7 @@ describe('plugin-metadata', () => {
setup: () => {}, setup: () => {},
}, { order: 10, name: test }) }, { order: 10, name: test })
` `
expect(transformPlugin.transform(plugin, 'my-plugin.mjs').code).toMatchInlineSnapshot(` expect(transformPlugin.transform.call({ parse }, plugin, 'my-plugin.mjs').code).toMatchInlineSnapshot(`
" "
export default defineNuxtPlugin({ export default defineNuxtPlugin({
setup: () => {}, setup: () => {},

View File

@ -340,9 +340,6 @@ importers:
'@types/node': '@types/node':
specifier: ^14.18.0 || >=16.10.0 specifier: ^14.18.0 || >=16.10.0
version: 18.16.18 version: 18.16.18
'@typescript-eslint/typescript-estree':
specifier: ^5.60.0
version: 5.60.0(typescript@5.0.4)
'@unhead/ssr': '@unhead/ssr':
specifier: ^1.1.27 specifier: ^1.1.27
version: 1.1.27 version: 1.1.27
@ -352,6 +349,9 @@ importers:
'@vue/shared': '@vue/shared':
specifier: ^3.3.4 specifier: ^3.3.4
version: 3.3.4 version: 3.3.4
acorn:
specifier: 8.9.0
version: 8.9.0
c12: c12:
specifier: ^1.4.2 specifier: ^1.4.2
version: 1.4.2 version: 1.4.2
@ -370,6 +370,9 @@ importers:
devalue: devalue:
specifier: ^4.3.2 specifier: ^4.3.2
version: 4.3.2 version: 4.3.2
esbuild:
specifier: ^0.18.6
version: 0.18.6
escape-string-regexp: escape-string-regexp:
specifier: ^5.0.0 specifier: ^5.0.0
version: 5.0.0 version: 5.0.0
@ -491,9 +494,6 @@ importers:
'@vitejs/plugin-vue': '@vitejs/plugin-vue':
specifier: 4.2.3 specifier: 4.2.3
version: 4.2.3(vite@4.3.9)(vue@3.3.4) version: 4.2.3(vite@4.3.9)(vue@3.3.4)
acorn:
specifier: 8.9.0
version: 8.9.0
unbuild: unbuild:
specifier: latest specifier: latest
version: 1.2.1 version: 1.2.1
@ -2610,11 +2610,6 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true dev: true
/@typescript-eslint/types@5.60.0:
resolution: {integrity: sha512-ascOuoCpNZBccFVNJRSC6rPq4EmJ2NkuoKnd6LDNyAQmdDnziAtxbCGWCbefG1CNzmDvd05zO36AmB7H8RzKPA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: false
/@typescript-eslint/typescript-estree@5.59.9(typescript@5.0.4): /@typescript-eslint/typescript-estree@5.59.9(typescript@5.0.4):
resolution: {integrity: sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==} resolution: {integrity: sha512-pmM0/VQ7kUhd1QyIxgS+aRvMgw+ZljB3eDb+jYyp6d2bC0mQWLzUDF+DLwCTkQ3tlNyVsvZRXjFyV0LkU/aXjA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -2636,27 +2631,6 @@ packages:
- supports-color - supports-color
dev: true dev: true
/@typescript-eslint/typescript-estree@5.60.0(typescript@5.0.4):
resolution: {integrity: sha512-R43thAuwarC99SnvrBmh26tc7F6sPa2B3evkXp/8q954kYL6Ro56AwASYWtEEi+4j09GbiNAHqYwNNZuNlARGQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
typescript: '*'
peerDependenciesMeta:
typescript:
optional: true
dependencies:
'@typescript-eslint/types': 5.60.0
'@typescript-eslint/visitor-keys': 5.60.0
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.3
tsutils: 3.21.0(typescript@5.0.4)
typescript: 5.0.4
transitivePeerDependencies:
- supports-color
dev: false
/@typescript-eslint/utils@5.59.9(eslint@8.43.0)(typescript@5.0.4): /@typescript-eslint/utils@5.59.9(eslint@8.43.0)(typescript@5.0.4):
resolution: {integrity: sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==} resolution: {integrity: sha512-1PuMYsju/38I5Ggblaeb98TOoUvjhRvLpLa1DoTOFaLWqaXl/1iQ1eGurTXgBY58NUdtfTXKP5xBq7q9NDaLKg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@ -2685,14 +2659,6 @@ packages:
eslint-visitor-keys: 3.4.1 eslint-visitor-keys: 3.4.1
dev: true dev: true
/@typescript-eslint/visitor-keys@5.60.0:
resolution: {integrity: sha512-wm9Uz71SbCyhUKgcaPRauBdTegUyY/ZWl8gLwD/i/ybJqscrrdVSFImpvUz16BLPChIeKBK5Fa9s6KDQjsjyWw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
'@typescript-eslint/types': 5.60.0
eslint-visitor-keys: 3.4.1
dev: false
/@unhead/dom@1.1.27: /@unhead/dom@1.1.27:
resolution: {integrity: sha512-sUrzpKIVvFp8TFx1mgp5t0k5ts1+KmgjMgRRuvRTZMBMVeGQRLSuL3uo34iwuFmKxeI6BXT5lVBk5H02c1XdGg==} resolution: {integrity: sha512-sUrzpKIVvFp8TFx1mgp5t0k5ts1+KmgjMgRRuvRTZMBMVeGQRLSuL3uo34iwuFmKxeI6BXT5lVBk5H02c1XdGg==}
dependencies: dependencies:
@ -3285,6 +3251,7 @@ packages:
/array-union@2.1.0: /array-union@2.1.0:
resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true
/array.prototype.flat@1.3.1: /array.prototype.flat@1.3.1:
resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==}
@ -5341,6 +5308,7 @@ packages:
ignore: 5.2.4 ignore: 5.2.4
merge2: 1.4.1 merge2: 1.4.1
slash: 3.0.0 slash: 3.0.0
dev: true
/globby@13.2.0: /globby@13.2.0:
resolution: {integrity: sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==} resolution: {integrity: sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==}
@ -7960,6 +7928,7 @@ packages:
/slash@3.0.0: /slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true
/slash@4.0.0: /slash@4.0.0:
resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==}
@ -8358,6 +8327,7 @@ packages:
/tslib@1.14.1: /tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
dev: true
/tslib@2.5.3: /tslib@2.5.3:
resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==}
@ -8370,6 +8340,7 @@ packages:
dependencies: dependencies:
tslib: 1.14.1 tslib: 1.14.1
typescript: 5.0.4 typescript: 5.0.4
dev: true
/tunnel@0.0.6: /tunnel@0.0.6:
resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==}