mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-22 11:22:43 +00:00
feat(nuxt): use oxc-parser
instead of esbuild + acorn
This commit is contained in:
parent
1c418d0ea3
commit
499ce3d5f3
@ -70,7 +70,6 @@
|
||||
"@unhead/ssr": "^1.11.13",
|
||||
"@unhead/vue": "^1.11.13",
|
||||
"@vue/shared": "^3.5.13",
|
||||
"acorn": "8.14.0",
|
||||
"c12": "^2.0.1",
|
||||
"chokidar": "^4.0.1",
|
||||
"compatx": "^0.1.8",
|
||||
@ -99,6 +98,7 @@
|
||||
"nypm": "^0.4.0",
|
||||
"ofetch": "^1.4.1",
|
||||
"ohash": "^1.1.4",
|
||||
"oxc-parser": "^0.38.0",
|
||||
"pathe": "^1.1.2",
|
||||
"perfect-debounce": "^1.0.0",
|
||||
"pkg-types": "^1.2.1",
|
||||
|
@ -1,13 +1,12 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { parseURL } from 'ufo'
|
||||
import MagicString from 'magic-string'
|
||||
import type { AssignmentProperty, CallExpression, ObjectExpression, Pattern, Property, ReturnStatement, VariableDeclaration } from 'estree'
|
||||
import type { Program } from 'acorn'
|
||||
import type { BindingPattern, BindingProperty, BindingRestElement, CallExpression, Expression, ObjectExpression, ObjectProperty, Program, ReturnStatement, VariableDeclaration } from 'oxc-parser'
|
||||
import { createUnplugin } from 'unplugin'
|
||||
import type { Component } from '@nuxt/schema'
|
||||
import { resolve } from 'pathe'
|
||||
|
||||
import { parseAndWalk, walk, withLocations } from '../../core/utils/parse'
|
||||
import { parseAndWalk, walk } from '../../core/utils/parse'
|
||||
import type { Node } from '../../core/utils/parse'
|
||||
import { distDir } from '../../dirs'
|
||||
|
||||
@ -58,15 +57,14 @@ export const TreeShakeTemplatePlugin = (options: TreeShakeTemplatePluginOptions)
|
||||
const [componentCall, _, children] = node.arguments
|
||||
if (!componentCall) { return }
|
||||
|
||||
if (componentCall.type === 'Identifier' || componentCall.type === 'MemberExpression' || componentCall.type === 'CallExpression') {
|
||||
if (componentCall.type === 'Identifier' || componentCall.type === 'ComputedMemberExpression' || componentCall.type === 'StaticMemberExpression' || componentCall.type === 'CallExpression') {
|
||||
const componentName = getComponentName(node)
|
||||
if (!componentName || !COMPONENTS_IDENTIFIERS_RE.test(componentName) || children?.type !== 'ObjectExpression') { return }
|
||||
|
||||
const isClientOnlyComponent = CLIENT_ONLY_NAME_RE.test(componentName)
|
||||
const slotsToRemove = isClientOnlyComponent ? children.properties.filter(prop => prop.type === 'Property' && prop.key.type === 'Identifier' && !PLACEHOLDER_EXACT_RE.test(prop.key.name)) as Property[] : children.properties as Property[]
|
||||
const slotsToRemove = isClientOnlyComponent ? children.properties.filter(prop => prop.type === 'ObjectProperty' && prop.key.type === 'Identifier' && !PLACEHOLDER_EXACT_RE.test(prop.key.name)) as ObjectProperty[] : children.properties as ObjectProperty[]
|
||||
|
||||
for (const _slot of slotsToRemove) {
|
||||
const slot = withLocations(_slot)
|
||||
for (const slot of slotsToRemove) {
|
||||
s.remove(slot.start, slot.end + 1)
|
||||
const removedCode = `({${code.slice(slot.start, slot.end + 1)}})`
|
||||
const currentState = s.toString()
|
||||
@ -87,7 +85,7 @@ export const TreeShakeTemplatePlugin = (options: TreeShakeTemplatePluginOptions)
|
||||
})
|
||||
|
||||
const componentsToRemove = [...componentsToRemoveSet]
|
||||
const removedNodes = new WeakSet<Node>()
|
||||
const removedNodes = new WeakSet<PropertyPattern>()
|
||||
|
||||
for (const componentName of componentsToRemove) {
|
||||
// remove import declaration if it exists
|
||||
@ -119,18 +117,18 @@ function removeFromSetupReturn (codeAst: Program, name: string, magicString: Mag
|
||||
enter (node) {
|
||||
if (walkedInSetup) {
|
||||
this.skip()
|
||||
} else if (node.type === 'Property' && node.key.type === 'Identifier' && node.key.name === 'setup' && (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
|
||||
} else if (node.type === 'ObjectProperty' && node.key.type === 'Identifier' && node.key.name === 'setup' && (node.value.type === 'FunctionExpression' || node.value.type === 'ArrowFunctionExpression')) {
|
||||
// walk into the setup function
|
||||
walkedInSetup = true
|
||||
if (node.value.body?.type === 'BlockStatement') {
|
||||
const returnStatement = node.value.body.body.find(statement => statement.type === 'ReturnStatement') as ReturnStatement
|
||||
if (node.value.body?.type === 'FunctionBody') {
|
||||
const returnStatement = node.value.body.statements.find(statement => statement.type === 'ReturnStatement') as ReturnStatement
|
||||
if (returnStatement && returnStatement.argument?.type === 'ObjectExpression') {
|
||||
// remove from return statement
|
||||
removePropertyFromObject(returnStatement.argument, name, magicString)
|
||||
}
|
||||
|
||||
// remove from __returned__
|
||||
const variableList = node.value.body.body.filter((statement): statement is VariableDeclaration => statement.type === 'VariableDeclaration')
|
||||
const variableList = node.value.body.statements.filter((statement): statement is VariableDeclaration => statement.type === 'VariableDeclaration')
|
||||
const returnedVariableDeclaration = variableList.find(declaration => declaration.declarations[0]?.id.type === 'Identifier' && declaration.declarations[0]?.id.name === '__returned__' && declaration.declarations[0]?.init?.type === 'ObjectExpression')
|
||||
if (returnedVariableDeclaration) {
|
||||
const init = returnedVariableDeclaration.declarations[0]?.init as ObjectExpression | undefined
|
||||
@ -149,9 +147,8 @@ function removeFromSetupReturn (codeAst: Program, name: string, magicString: Mag
|
||||
*/
|
||||
function removePropertyFromObject (node: ObjectExpression, name: string, magicString: MagicString) {
|
||||
for (const property of node.properties) {
|
||||
if (property.type === 'Property' && property.key.type === 'Identifier' && property.key.name === name) {
|
||||
const _property = withLocations(property)
|
||||
magicString.remove(_property.start, _property.end + 1)
|
||||
if (property.type === 'ObjectProperty' && property.key.type === 'Identifier' && property.key.name === name) {
|
||||
magicString.remove(property.start, property.end + 1)
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -173,12 +170,10 @@ function removeImportDeclaration (ast: Program, importName: string, magicString:
|
||||
const specifierIndex = node.specifiers.findIndex(s => s.local.name === importName)
|
||||
if (specifierIndex > -1) {
|
||||
if (node.specifiers!.length > 1) {
|
||||
const specifier = withLocations(node.specifiers![specifierIndex])
|
||||
magicString.remove(specifier.start, specifier.end + 1)
|
||||
magicString.remove((node.specifiers![specifierIndex])!.start, (node.specifiers![specifierIndex])!.end + 1)
|
||||
node.specifiers!.splice(specifierIndex, 1)
|
||||
} else {
|
||||
const specifier = withLocations(node)
|
||||
magicString.remove(specifier.start, specifier.end)
|
||||
magicString.remove(node.start, node.end)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -195,7 +190,7 @@ function isComponentNotCalledInSetup (code: string, id: string, name: string): s
|
||||
if (!name) { return }
|
||||
let found = false
|
||||
parseAndWalk(code, id, function (node) {
|
||||
if ((node.type === 'Property' && node.key.type === 'Identifier' && node.value.type === 'FunctionExpression' && node.key.name === 'setup') || (node.type === 'FunctionDeclaration' && (node.id?.name === '_sfc_ssrRender' || node.id?.name === 'ssrRender'))) {
|
||||
if ((node.type === 'ObjectProperty' && node.key.type === 'Identifier' && node.value.type === 'FunctionExpression' && node.key.name === 'setup') || (node.type === 'FunctionDeclaration' && (node.id?.name === '_sfc_ssrRender' || node.id?.name === 'ssrRender'))) {
|
||||
// walk through the setup function node or the ssrRender function
|
||||
walk(node, {
|
||||
enter (node) {
|
||||
@ -203,9 +198,11 @@ function isComponentNotCalledInSetup (code: string, id: string, name: string): s
|
||||
this.skip()
|
||||
} else if (node.type === 'Identifier' && node.name === name) {
|
||||
found = true
|
||||
} else if (node.type === 'MemberExpression') {
|
||||
} else if (node.type === 'StaticMemberExpression') {
|
||||
// dev only with $setup or _ctx
|
||||
found = (node.property.type === 'Literal' && node.property.value === name) || (node.property.type === 'Identifier' && node.property.name === name)
|
||||
found = (node.property.type === 'Identifier' && node.property.name === name)
|
||||
} else if (node.type === 'ComputedMemberExpression') {
|
||||
found = (node.expression.type === 'Literal' && node.expression.value === name)
|
||||
}
|
||||
},
|
||||
})
|
||||
@ -224,10 +221,10 @@ function getComponentName (ssrRenderNode: CallExpression): string | undefined {
|
||||
|
||||
if (componentCall.type === 'Identifier') {
|
||||
return componentCall.name
|
||||
} else if (componentCall.type === 'MemberExpression') {
|
||||
if (componentCall.property.type === 'Literal') {
|
||||
return componentCall.property.value as string
|
||||
}
|
||||
} else if (componentCall.type === 'StaticMemberExpression') {
|
||||
return componentCall.property.name
|
||||
} else if (componentCall.type === 'ComputedMemberExpression' && componentCall.expression.type === 'Literal') {
|
||||
return componentCall.expression.value as string
|
||||
} else if (componentCall.type === 'CallExpression') {
|
||||
return getComponentName(componentCall)
|
||||
}
|
||||
@ -236,14 +233,14 @@ function getComponentName (ssrRenderNode: CallExpression): string | undefined {
|
||||
/**
|
||||
* remove a variable declaration within the code
|
||||
*/
|
||||
function removeVariableDeclarator (codeAst: Program, name: string, magicString: MagicString, removedNodes: WeakSet<Node>): Node | void {
|
||||
function removeVariableDeclarator (codeAst: Program, name: string, magicString: MagicString, removedNodes: WeakSet<PropertyPattern>): Expression | void {
|
||||
// remove variables
|
||||
walk(codeAst, {
|
||||
enter (node) {
|
||||
if (node.type !== 'VariableDeclaration') { return }
|
||||
for (const declarator of node.declarations) {
|
||||
const toRemove = withLocations(findMatchingPatternToRemove(declarator.id, node, name, removedNodes))
|
||||
if (toRemove) {
|
||||
const toRemove = findMatchingPatternToRemove(declarator.id, node, name, removedNodes)
|
||||
if (toRemove && 'start' in toRemove) {
|
||||
magicString.remove(toRemove.start, toRemove.end + 1)
|
||||
removedNodes.add(toRemove)
|
||||
}
|
||||
@ -255,23 +252,24 @@ function removeVariableDeclarator (codeAst: Program, name: string, magicString:
|
||||
/**
|
||||
* find the Pattern to remove which the identifier is equal to the name parameter.
|
||||
*/
|
||||
function findMatchingPatternToRemove (node: Pattern, toRemoveIfMatched: Node, name: string, removedNodeSet: WeakSet<Node>): Node | undefined {
|
||||
type PropertyPattern = BindingPattern | BindingRestElement | BindingProperty | Node
|
||||
function findMatchingPatternToRemove (node: PropertyPattern, toRemoveIfMatched: PropertyPattern, name: string, removedNodeSet: WeakSet<PropertyPattern>): PropertyPattern | undefined {
|
||||
if (node.type === 'Identifier') {
|
||||
if (node.name === name) {
|
||||
return toRemoveIfMatched
|
||||
}
|
||||
} else if (node.type === 'ArrayPattern') {
|
||||
const elements = node.elements.filter((e): e is Pattern => e !== null && !removedNodeSet.has(e))
|
||||
const elements = node.elements.filter((e): e is BindingPattern | BindingRestElement => e !== null && !removedNodeSet.has(e))
|
||||
|
||||
for (const element of elements) {
|
||||
const matched = findMatchingPatternToRemove(element, elements.length > 1 ? element : toRemoveIfMatched, name, removedNodeSet)
|
||||
if (matched) { return matched }
|
||||
}
|
||||
} else if (node.type === 'ObjectPattern') {
|
||||
const properties = node.properties.filter((e): e is AssignmentProperty => e.type === 'Property' && !removedNodeSet.has(e))
|
||||
const properties = node.properties.filter((e): e is BindingProperty => e.type === 'BindingProperty' && !removedNodeSet.has(e))
|
||||
|
||||
for (const [index, property] of properties.entries()) {
|
||||
let nodeToRemove: Node = property
|
||||
let nodeToRemove: PropertyPattern = property
|
||||
if (properties.length < 2) {
|
||||
nodeToRemove = toRemoveIfMatched
|
||||
}
|
||||
|
@ -248,15 +248,13 @@ function resolvePaths<Item extends Record<string, any>> (items: Item[], key: { [
|
||||
}))
|
||||
}
|
||||
|
||||
const IS_TSX = /\.[jt]sx$/
|
||||
|
||||
export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
|
||||
const _plugins: Array<NuxtPlugin & Omit<PluginMeta, 'enforce'>> = []
|
||||
for (const plugin of plugins) {
|
||||
try {
|
||||
const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src]! : await fsp.readFile(plugin.src!, 'utf-8')
|
||||
_plugins.push({
|
||||
...await extractMetadata(code, IS_TSX.test(plugin.src) ? 'tsx' : 'ts'),
|
||||
...await extractMetadata(code, plugin.src),
|
||||
...plugin,
|
||||
})
|
||||
} catch (e) {
|
||||
|
@ -3,13 +3,13 @@ import { createUnplugin } from 'unplugin'
|
||||
import { isAbsolute, relative } from 'pathe'
|
||||
import MagicString from 'magic-string'
|
||||
import { hash } from 'ohash'
|
||||
import type { Pattern } from 'estree'
|
||||
import { parseQuery, parseURL } from 'ufo'
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { findStaticImports, parseStaticImport } from 'mlly'
|
||||
import { parseAndWalk, walk } from '../../core/utils/parse'
|
||||
import type { BindingPattern } from 'oxc-parser'
|
||||
|
||||
import { matchWithStringOrRegex } from '../utils/plugins'
|
||||
import { parseAndWalk, walk } from '../utils/parse'
|
||||
|
||||
interface ComposableKeysOptions {
|
||||
sourcemap: boolean
|
||||
@ -62,8 +62,10 @@ export const ComposableKeysPlugin = (options: ComposableKeysOptions) => createUn
|
||||
varCollector.refresh(scopeTracker.curScopeKey)
|
||||
} else if (node.type === 'FunctionDeclaration' && node.id) {
|
||||
varCollector.addVar(node.id.name)
|
||||
} else if (node.type === 'VariableDeclarator') {
|
||||
varCollector.collect(node.id)
|
||||
} else if (node.type === 'VariableDeclaration') {
|
||||
for (const declaration of node.declarations) {
|
||||
varCollector.collect(declaration.id)
|
||||
}
|
||||
}
|
||||
},
|
||||
leave (_node) {
|
||||
@ -213,11 +215,9 @@ class ScopedVarsCollector {
|
||||
return false
|
||||
}
|
||||
|
||||
collect (pattern: Pattern) {
|
||||
collect (pattern: BindingPattern) {
|
||||
if (pattern.type === 'Identifier') {
|
||||
this.addVar(pattern.name)
|
||||
} else if (pattern.type === 'RestElement') {
|
||||
this.collect(pattern.argument)
|
||||
} else if (pattern.type === 'AssignmentPattern') {
|
||||
this.collect(pattern.left)
|
||||
} else if (pattern.type === 'ArrayPattern') {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import type { Literal, Property, SpreadElement } from 'estree'
|
||||
import { transform } from 'esbuild'
|
||||
import type { ObjectProperty, SpreadElement, StringLiteral } from 'oxc-parser'
|
||||
import { defu } from 'defu'
|
||||
import { findExports } from 'mlly'
|
||||
import type { Nuxt } from '@nuxt/schema'
|
||||
@ -8,7 +7,7 @@ import MagicString from 'magic-string'
|
||||
import { normalize } from 'pathe'
|
||||
import { logger } from '@nuxt/kit'
|
||||
|
||||
import { parseAndWalk, withLocations } from '../../core/utils/parse'
|
||||
import { parseAndWalk } from '../../core/utils/parse'
|
||||
|
||||
import type { ObjectPlugin, PluginMeta } from '#app'
|
||||
|
||||
@ -40,13 +39,12 @@ export const orderMap: Record<NonNullable<ObjectPlugin['enforce']>, number> = {
|
||||
}
|
||||
|
||||
const metaCache: Record<string, Omit<PluginMeta, 'enforce'>> = {}
|
||||
export async function extractMetadata (code: string, loader = 'ts' as 'ts' | 'tsx') {
|
||||
export function extractMetadata (code: string, id: string) {
|
||||
let meta: PluginMeta = {}
|
||||
if (metaCache[code]) {
|
||||
return metaCache[code]
|
||||
}
|
||||
const js = await transform(code, { loader })
|
||||
parseAndWalk(js.code, `file.${loader}`, (node) => {
|
||||
parseAndWalk(code, id, (node) => {
|
||||
if (node.type !== 'CallExpression' || node.callee.type !== 'Identifier') { return }
|
||||
|
||||
const name = 'name' in node.callee && node.callee.name
|
||||
@ -87,7 +85,7 @@ function isMetadataKey (key: string): key is PluginMetaKey {
|
||||
return key in keys
|
||||
}
|
||||
|
||||
function extractMetaFromObject (properties: Array<Property | SpreadElement>) {
|
||||
function extractMetaFromObject (properties: Array<ObjectProperty | SpreadElement>) {
|
||||
const meta: PluginMeta = {}
|
||||
for (const property of properties) {
|
||||
if (property.type === 'SpreadElement' || !('name' in property.key)) {
|
||||
@ -105,7 +103,7 @@ function extractMetaFromObject (properties: Array<Property | SpreadElement>) {
|
||||
if (property.value.elements.some(e => !e || e.type !== 'Literal' || typeof e.value !== 'string')) {
|
||||
throw new Error('dependsOn must take an array of string literals')
|
||||
}
|
||||
meta[propertyKey] = property.value.elements.map(e => (e as Literal)!.value as string)
|
||||
meta[propertyKey] = property.value.elements.map(e => (e as StringLiteral)!.value as string)
|
||||
}
|
||||
}
|
||||
return meta
|
||||
@ -163,10 +161,11 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
|
||||
|
||||
const propertyKey = property.key.name
|
||||
if (propertyKey === 'order' || propertyKey === 'enforce' || propertyKey === 'name') {
|
||||
const nextNode = arg.properties[propertyIndex + 1] || node.arguments[argIndex + 1]
|
||||
const nextIndex = withLocations(nextNode)?.start || (withLocations(arg).end - 1)
|
||||
const _nextNode = arg.properties[propertyIndex + 1] || node.arguments[argIndex + 1]
|
||||
const nextNode = _nextNode as typeof _nextNode & { start: number, end: number }
|
||||
const nextIndex = nextNode?.start || (arg.end - 1)
|
||||
|
||||
s.remove(withLocations(property).start, nextIndex)
|
||||
s.remove(property.start, nextIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { createUnplugin } from 'unplugin'
|
||||
import MagicString from 'magic-string'
|
||||
import { hash } from 'ohash'
|
||||
|
||||
import { parseAndWalk, withLocations } from '../../core/utils/parse'
|
||||
import { parseAndWalk } from '../../core/utils/parse'
|
||||
import { isJS, isVue } from '../utils'
|
||||
|
||||
export function PrehydrateTransformPlugin (options: { sourcemap?: boolean } = {}) {
|
||||
@ -23,11 +23,11 @@ export function PrehydrateTransformPlugin (options: { sourcemap?: boolean } = {}
|
||||
return
|
||||
}
|
||||
if (node.callee.name === 'onPrehydrate') {
|
||||
const callback = withLocations(node.arguments[0])
|
||||
const callback = node.arguments[0]
|
||||
if (!callback) { return }
|
||||
if (callback.type !== 'ArrowFunctionExpression' && callback.type !== 'FunctionExpression') { return }
|
||||
|
||||
const needsAttr = callback.params.length > 0
|
||||
const needsAttr = callback.params.items.length > 0
|
||||
|
||||
const p = transform(`forEach(${code.slice(callback.start, callback.end)})`, { loader: 'ts', minify: true })
|
||||
promises.push(p.then(({ code: result }) => {
|
||||
|
@ -1,33 +1,37 @@
|
||||
import { parseSync } from 'oxc-parser'
|
||||
import type { CatchClause, ClassBody, Declaration, Expression, MethodDefinition, ModuleDeclaration, ObjectProperty, Pattern, PrivateIdentifier, Program, PropertyDefinition, SpreadElement, Statement, Super, SwitchCase, TemplateElement } from 'oxc-parser'
|
||||
import { walk as _walk } from 'estree-walker'
|
||||
import type { Node, SyncHandler } from 'estree-walker'
|
||||
import type { Program as ESTreeProgram } from 'estree'
|
||||
import { parse } from 'acorn'
|
||||
import type { Program } from 'acorn'
|
||||
import type { SyncHandler } from 'estree-walker'
|
||||
import type { Node as ESTreeNode, Program as ESTreeProgram, ModuleSpecifier } from 'estree'
|
||||
|
||||
export type { Node }
|
||||
/** estree also has AssignmentProperty, Identifier and Literal as possible node types */
|
||||
export type Node = Declaration | Expression | ClassBody | CatchClause | MethodDefinition | ModuleDeclaration | ModuleSpecifier | Pattern | PrivateIdentifier | Program | SpreadElement | Statement | Super | SwitchCase | TemplateElement | ObjectProperty | PropertyDefinition
|
||||
|
||||
type WithLocations<T> = T & { start: number, end: number }
|
||||
type WalkerCallback = (this: ThisParameterType<SyncHandler>, node: WithLocations<Node>, parent: WithLocations<Node> | null, ctx: { key: string | number | symbol | null | undefined, index: number | null | undefined, ast: Program | Node }) => void
|
||||
type InferThis<T extends (...args: any[]) => any> = T extends (this: infer U, ...args: infer A) => any ? U : unknown
|
||||
|
||||
type WalkerCallback = (this: InferThis<SyncHandler>, node: Node, parent: Node | null, ctx: { key: string | number | symbol | null | undefined, index: number | null | undefined, ast: Program | Node }) => void
|
||||
|
||||
export function walk (ast: Program | Node, callback: { enter?: WalkerCallback, leave?: WalkerCallback }) {
|
||||
return _walk(ast as unknown as ESTreeProgram | Node, {
|
||||
return _walk(ast as unknown as ESTreeProgram | ESTreeNode, {
|
||||
enter (node, parent, key, index) {
|
||||
callback.enter?.call(this, node as WithLocations<Node>, parent as WithLocations<Node> | null, { key, index, ast })
|
||||
callback.enter?.call(this, node as Node, parent as Node | null, { key, index, ast })
|
||||
},
|
||||
leave (node, parent, key, index) {
|
||||
callback.leave?.call(this, node as WithLocations<Node>, parent as WithLocations<Node> | null, { key, index, ast })
|
||||
callback.leave?.call(this, node as Node, parent as Node | null, { key, index, ast })
|
||||
},
|
||||
}) as Program | Node | null
|
||||
})
|
||||
}
|
||||
|
||||
export function parseAndWalk (code: string, sourceFilename: string, callback: WalkerCallback): Program
|
||||
export function parseAndWalk (code: string, sourceFilename: string, object: { enter?: WalkerCallback, leave?: WalkerCallback }): Program
|
||||
export function parseAndWalk (code: string, _sourceFilename: string, callback: { enter?: WalkerCallback, leave?: WalkerCallback } | WalkerCallback) {
|
||||
const ast = parse (code, { sourceType: 'module', ecmaVersion: 'latest', locations: true })
|
||||
export function parseAndWalk (code: string, sourceFilename: string, callback: { enter?: WalkerCallback, leave?: WalkerCallback } | WalkerCallback) {
|
||||
const ast = parseSync(code, { sourceType: 'module', sourceFilename }).program
|
||||
walk(ast, typeof callback === 'function' ? { enter: callback } : callback)
|
||||
return ast
|
||||
}
|
||||
|
||||
type WithLocations<T> = T & { start: number, end: number }
|
||||
|
||||
export function withLocations<T> (node: T): WithLocations<T> {
|
||||
return node as WithLocations<T>
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ export default defineNuxtModule({
|
||||
const glob = pageToGlobMap[path]
|
||||
const code = path in nuxt.vfs ? nuxt.vfs[path]! : await readFile(path!, 'utf-8')
|
||||
try {
|
||||
const extractedRule = await extractRouteRules(code, path)
|
||||
const extractedRule = extractRouteRules(code, path)
|
||||
if (extractedRule) {
|
||||
if (!glob) {
|
||||
const relativePath = relative(nuxt.options.srcDir, path)
|
||||
|
@ -3,12 +3,11 @@ import { createUnplugin } from 'unplugin'
|
||||
import { parseQuery, parseURL } from 'ufo'
|
||||
import type { StaticImport } from 'mlly'
|
||||
import { findExports, findStaticImports, parseStaticImport } from 'mlly'
|
||||
import { walk } from 'estree-walker'
|
||||
import MagicString from 'magic-string'
|
||||
import { isAbsolute } from 'pathe'
|
||||
import { logger } from '@nuxt/kit'
|
||||
|
||||
import { parseAndWalk, withLocations } from '../../core/utils/parse'
|
||||
import { parseAndWalk, walk } from '../../core/utils/parse'
|
||||
|
||||
interface PageMetaPluginOptions {
|
||||
dev?: boolean
|
||||
@ -116,7 +115,7 @@ export const PageMetaPlugin = (options: PageMetaPluginOptions = {}) => createUnp
|
||||
if (node.type !== 'CallExpression' || node.callee.type !== 'Identifier') { return }
|
||||
if (!('name' in node.callee) || node.callee.name !== 'definePageMeta') { return }
|
||||
|
||||
const meta = withLocations(node.arguments[0])
|
||||
const meta = node.arguments[0]
|
||||
|
||||
if (!meta) { return }
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { runInNewContext } from 'node:vm'
|
||||
import { transform } from 'esbuild'
|
||||
import type { NuxtPage } from '@nuxt/schema'
|
||||
import type { NitroRouteConfig } from 'nitro/types'
|
||||
import { normalize } from 'pathe'
|
||||
@ -11,7 +10,7 @@ import { extractScriptContent, pathToNitroGlob } from './utils'
|
||||
const ROUTE_RULE_RE = /\bdefineRouteRules\(/
|
||||
const ruleCache: Record<string, NitroRouteConfig | null> = {}
|
||||
|
||||
export async function extractRouteRules (code: string, path: string): Promise<NitroRouteConfig | null> {
|
||||
export function extractRouteRules (code: string, path: string): NitroRouteConfig | null {
|
||||
if (code in ruleCache) {
|
||||
return ruleCache[code] || null
|
||||
}
|
||||
@ -27,12 +26,10 @@ export async function extractRouteRules (code: string, path: string): Promise<Ni
|
||||
|
||||
code = script?.code || code
|
||||
|
||||
const js = await transform(code, { loader: script?.loader || 'ts' })
|
||||
|
||||
parseAndWalk(js.code, 'file.' + (script?.loader || 'ts'), (node) => {
|
||||
parseAndWalk(code, 'file.' + (script?.loader || 'ts'), (node) => {
|
||||
if (node.type !== 'CallExpression' || node.callee.type !== 'Identifier') { return }
|
||||
if (node.callee.name === 'defineRouteRules') {
|
||||
const rulesString = js.code.slice(node.start, node.end)
|
||||
const rulesString = code.slice(node.start, node.end)
|
||||
try {
|
||||
rule = JSON.parse(runInNewContext(rulesString.replace('defineRouteRules', 'JSON.stringify'), {}))
|
||||
} catch {
|
||||
|
@ -7,8 +7,7 @@ import { genArrayFromRaw, genDynamicImport, genImport, genSafeVariableName } fro
|
||||
import escapeRE from 'escape-string-regexp'
|
||||
import { filename } from 'pathe/utils'
|
||||
import { hash } from 'ohash'
|
||||
import { transform } from 'esbuild'
|
||||
import type { Property } from 'estree'
|
||||
import type { ObjectProperty } from 'oxc-parser'
|
||||
import type { NuxtPage } from 'nuxt/schema'
|
||||
|
||||
import { parseAndWalk } from '../core/utils/parse'
|
||||
@ -166,7 +165,7 @@ export async function augmentPages (routes: NuxtPage[], vfs: Record<string, stri
|
||||
for (const route of routes) {
|
||||
if (route.file && !ctx.pagesToSkip?.has(route.file)) {
|
||||
const fileContent = route.file in vfs ? vfs[route.file]! : fs.readFileSync(await resolvePath(route.file), 'utf-8')
|
||||
const routeMeta = await getRouteMeta(fileContent, route.file, ctx.extraExtractionKeys)
|
||||
const routeMeta = getRouteMeta(fileContent, route.file, ctx.extraExtractionKeys)
|
||||
if (route.meta) {
|
||||
routeMeta.meta = { ...routeMeta.meta, ...route.meta }
|
||||
}
|
||||
@ -203,7 +202,7 @@ const DYNAMIC_META_KEY = '__nuxt_dynamic_meta_key' as const
|
||||
|
||||
const pageContentsCache: Record<string, string> = {}
|
||||
const metaCache: Record<string, Partial<Record<keyof NuxtPage, any>>> = {}
|
||||
export async function getRouteMeta (contents: string, absolutePath: string, extraExtractionKeys: string[] = []): Promise<Partial<Record<keyof NuxtPage, any>>> {
|
||||
export function getRouteMeta (contents: string, absolutePath: string, extraExtractionKeys: string[] = []): Partial<Record<keyof NuxtPage, any>> {
|
||||
// set/update pageContentsCache, invalidate metaCache on cache mismatch
|
||||
if (!(absolutePath in pageContentsCache) || pageContentsCache[absolutePath] !== contents) {
|
||||
pageContentsCache[absolutePath] = contents
|
||||
@ -230,13 +229,11 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr
|
||||
continue
|
||||
}
|
||||
|
||||
const js = await transform(script.code, { loader: script.loader })
|
||||
|
||||
const dynamicProperties = new Set<keyof NuxtPage>()
|
||||
|
||||
let foundMeta = false
|
||||
|
||||
parseAndWalk(js.code, absolutePath.replace(/\.\w+$/, '.' + script.loader), (node) => {
|
||||
parseAndWalk(script.code, absolutePath.replace(/\.\w+$/, '.' + script.loader), (node) => {
|
||||
if (foundMeta) { return }
|
||||
|
||||
if (node.type !== 'ExpressionStatement' || node.expression.type !== 'CallExpression' || node.expression.callee.type !== 'Identifier' || node.expression.callee.name !== 'definePageMeta') { return }
|
||||
@ -246,11 +243,11 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr
|
||||
if (pageMetaArgument?.type !== 'ObjectExpression') { return }
|
||||
|
||||
for (const key of extractionKeys) {
|
||||
const property = pageMetaArgument.properties.find((property): property is Property => property.type === 'Property' && property.key.type === 'Identifier' && property.key.name === key)
|
||||
const property = pageMetaArgument.properties.find((property): property is ObjectProperty => property.type === 'ObjectProperty' && property.key.type === 'Identifier' && property.key.name === key)
|
||||
if (!property) { continue }
|
||||
|
||||
if (property.value.type === 'ObjectExpression') {
|
||||
const valueString = js.code.slice(property.value.range![0], property.value.range![1])
|
||||
const valueString = script.code.slice(property.value.start, property.value.end)
|
||||
try {
|
||||
extractedMeta[key] = JSON.parse(runInNewContext(`JSON.stringify(${valueString})`, {}))
|
||||
} catch {
|
||||
@ -286,7 +283,7 @@ export async function getRouteMeta (contents: string, absolutePath: string, extr
|
||||
}
|
||||
|
||||
for (const property of pageMetaArgument.properties) {
|
||||
if (property.type !== 'Property') {
|
||||
if (property.type !== 'ObjectProperty') {
|
||||
continue
|
||||
}
|
||||
const isIdentifierOrLiteral = property.key.type === 'Literal' || property.key.type === 'Identifier'
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { Component } from '@nuxt/schema'
|
||||
import { compileScript, parse } from '@vue/compiler-sfc'
|
||||
import * as Parser from 'acorn'
|
||||
|
||||
import { ComponentNamePlugin } from '../src/components/plugins/component-names'
|
||||
|
||||
@ -22,14 +21,7 @@ onMounted(() => {
|
||||
</script>
|
||||
`
|
||||
const res = compileScript(parse(sfc).descriptor, { id: 'test.vue' })
|
||||
const { code } = transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, res.content, components[0].filePath) ?? {}
|
||||
const { code } = transformPlugin.transform(res.content, components[0].filePath) ?? {}
|
||||
expect(code?.trim()).toMatchInlineSnapshot(`
|
||||
"export default Object.assign({
|
||||
setup(__props, { expose: __expose }) {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import * as Parser from 'acorn'
|
||||
|
||||
import { ComposableKeysPlugin, detectImportNames } from '../src/core/plugins/composable-keys'
|
||||
|
||||
@ -40,14 +39,7 @@ describe('composable keys plugin', () => {
|
||||
import { useAsyncData } from '#app'
|
||||
useAsyncData(() => {})
|
||||
`
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`
|
||||
expect(transformPlugin.transform(code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`
|
||||
"import { useAsyncData } from '#app'
|
||||
useAsyncData(() => {}, '$yXewDLZblH')"
|
||||
`)
|
||||
@ -55,14 +47,7 @@ useAsyncData(() => {})
|
||||
|
||||
it('should not add hash when one exists', () => {
|
||||
const code = `useAsyncData(() => {}, 'foo')`
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`undefined`)
|
||||
expect(transformPlugin.transform(code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`undefined`)
|
||||
})
|
||||
|
||||
it('should not add hash composables is imported from somewhere else', () => {
|
||||
@ -70,13 +55,6 @@ useAsyncData(() => {})
|
||||
const useAsyncData = () => {}
|
||||
useAsyncData(() => {})
|
||||
`
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`undefined`)
|
||||
expect(transformPlugin.transform(code, 'plugin.ts')?.code.trim()).toMatchInlineSnapshot(`undefined`)
|
||||
})
|
||||
})
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { compileScript, parse } from '@vue/compiler-sfc'
|
||||
import * as Parser from 'acorn'
|
||||
|
||||
import { PageMetaPlugin } from '../src/pages/plugins/page-meta'
|
||||
import { getRouteMeta, normalizeRoutes } from '../src/pages/utils'
|
||||
@ -9,22 +8,22 @@ import type { NuxtPage } from '../schema'
|
||||
const filePath = '/app/pages/index.vue'
|
||||
|
||||
describe('page metadata', () => {
|
||||
it('should not extract metadata from empty files', async () => {
|
||||
expect(await getRouteMeta('', filePath)).toEqual({})
|
||||
expect(await getRouteMeta('<template><div>Hi</div></template>', filePath)).toEqual({})
|
||||
it('should not extract metadata from empty files', () => {
|
||||
expect(getRouteMeta('', filePath)).toEqual({})
|
||||
expect(getRouteMeta('<template><div>Hi</div></template>', filePath)).toEqual({})
|
||||
})
|
||||
|
||||
it('should extract metadata from JS/JSX files', async () => {
|
||||
it('should extract metadata from JS/JSX files', () => {
|
||||
const fileContents = `definePageMeta({ name: 'bar' })`
|
||||
for (const ext of ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs']) {
|
||||
const meta = await getRouteMeta(fileContents, `/app/pages/index.${ext}`)
|
||||
const meta = getRouteMeta(fileContents, `/app/pages/index.${ext}`)
|
||||
expect(meta).toStrictEqual({
|
||||
name: 'bar',
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it('should parse JSX files', async () => {
|
||||
it('should parse JSX files', () => {
|
||||
const fileContents = `
|
||||
export default {
|
||||
setup () {
|
||||
@ -33,14 +32,13 @@ export default {
|
||||
}
|
||||
}
|
||||
`
|
||||
const meta = await getRouteMeta(fileContents, `/app/pages/index.jsx`)
|
||||
const meta = getRouteMeta(fileContents, `/app/pages/index.jsx`)
|
||||
expect(meta).toStrictEqual({
|
||||
name: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
// TODO: https://github.com/nuxt/nuxt/pull/30066
|
||||
it.todo('should handle experimental decorators', async () => {
|
||||
it('should handle experimental decorators', async () => {
|
||||
const fileContents = `
|
||||
<script setup lang="ts">
|
||||
function something (_method: () => unknown) {
|
||||
@ -69,8 +67,37 @@ definePageMeta({ name: 'bar' })
|
||||
expect(meta === await getRouteMeta('<template><div>Hi</div></template>' + fileContents, filePath)).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata', async () => {
|
||||
const meta = await getRouteMeta(`
|
||||
it('should handle experimental decorators', () => {
|
||||
const fileContents = `
|
||||
<script setup lang="ts">
|
||||
function something (_method: () => unknown) {
|
||||
return () => 'decorated'
|
||||
}
|
||||
class SomeClass {
|
||||
@something
|
||||
public someMethod () {
|
||||
return 'initial'
|
||||
}
|
||||
}
|
||||
definePageMeta({ name: 'bar' })
|
||||
</script>
|
||||
`
|
||||
const meta = getRouteMeta(fileContents, `/app/pages/index.vue`)
|
||||
expect(meta).toStrictEqual({
|
||||
name: 'bar',
|
||||
})
|
||||
})
|
||||
|
||||
it('should use and invalidate cache', () => {
|
||||
const fileContents = `<script setup>definePageMeta({ foo: 'bar' })</script>`
|
||||
const meta = getRouteMeta(fileContents, filePath)
|
||||
expect(meta === getRouteMeta(fileContents, filePath)).toBeTruthy()
|
||||
expect(meta === getRouteMeta(fileContents, '/app/pages/other.vue')).toBeFalsy()
|
||||
expect(meta === getRouteMeta('<template><div>Hi</div></template>' + fileContents, filePath)).toBeFalsy()
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata', () => {
|
||||
const meta = getRouteMeta(`
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
name: 'some-custom-name',
|
||||
@ -99,8 +126,8 @@ definePageMeta({ name: 'bar' })
|
||||
`)
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata from files with multiple blocks', async () => {
|
||||
const meta = await getRouteMeta(`
|
||||
it('should extract serialisable metadata from files with multiple blocks', () => {
|
||||
const meta = getRouteMeta(`
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'thing'
|
||||
@ -134,8 +161,8 @@ definePageMeta({ name: 'bar' })
|
||||
`)
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata in options api', async () => {
|
||||
const meta = await getRouteMeta(`
|
||||
it('should extract serialisable metadata in options api', () => {
|
||||
const meta = getRouteMeta(`
|
||||
<script>
|
||||
export default {
|
||||
setup() {
|
||||
@ -162,8 +189,8 @@ definePageMeta({ name: 'bar' })
|
||||
`)
|
||||
})
|
||||
|
||||
it('should extract serialisable metadata all quoted', async () => {
|
||||
const meta = await getRouteMeta(`
|
||||
it('should extract serialisable metadata all quoted', () => {
|
||||
const meta = getRouteMeta(`
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
"otherValue": {
|
||||
@ -204,9 +231,9 @@ definePageMeta({ name: 'bar' })
|
||||
})
|
||||
|
||||
describe('normalizeRoutes', () => {
|
||||
it('should produce valid route objects when used with extracted meta', async () => {
|
||||
it('should produce valid route objects when used with extracted meta', () => {
|
||||
const page: NuxtPage = { path: '/', file: filePath }
|
||||
Object.assign(page, await getRouteMeta(`
|
||||
Object.assign(page, getRouteMeta(`
|
||||
<script setup>
|
||||
definePageMeta({
|
||||
name: 'some-custom-name',
|
||||
@ -295,14 +322,7 @@ definePageMeta({
|
||||
</script>
|
||||
`
|
||||
const res = compileScript(parse(sfc).descriptor, { id: 'component.vue' })
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, res.content, 'component.vue?macro=true')?.code).toMatchInlineSnapshot(`
|
||||
expect(transformPlugin.transform(res.content, 'component.vue?macro=true')?.code).toMatchInlineSnapshot(`
|
||||
"const __nuxt_page_meta = {
|
||||
name: 'hi',
|
||||
other: 'value'
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import * as Parser from 'acorn'
|
||||
|
||||
import { RemovePluginMetadataPlugin, extractMetadata } from '../src/core/plugins/plugin-metadata'
|
||||
import { checkForCircularDependencies } from '../src/core/app'
|
||||
@ -21,7 +20,7 @@ describe('plugin-metadata', () => {
|
||||
'export default defineNuxtPlugin({',
|
||||
...obj.map(([key, value]) => `${key}: ${typeof value === 'function' ? value.toString().replace('"[JSX]"', '() => <span>JSX</span>') : JSON.stringify(value)},`),
|
||||
'})',
|
||||
].join('\n'), 'tsx')
|
||||
].join('\n'), 'file.tsx')
|
||||
|
||||
expect(meta).toEqual({
|
||||
'name': 'test',
|
||||
@ -40,14 +39,7 @@ describe('plugin-metadata', () => {
|
||||
'export const plugin = {}',
|
||||
]
|
||||
for (const plugin of invalidPlugins) {
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, plugin, 'my-plugin.mjs').code).toBe('export default () => {}')
|
||||
expect(transformPlugin.transform(plugin, 'my-plugin.mjs').code).toBe('export default () => {}')
|
||||
}
|
||||
})
|
||||
|
||||
@ -59,14 +51,7 @@ describe('plugin-metadata', () => {
|
||||
setup: () => {},
|
||||
}, { order: 10, name: test })
|
||||
`
|
||||
expect(transformPlugin.transform.call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, plugin, 'my-plugin.mjs').code).toMatchInlineSnapshot(`
|
||||
expect(transformPlugin.transform(plugin, 'my-plugin.mjs').code).toMatchInlineSnapshot(`
|
||||
"
|
||||
export default defineNuxtPlugin({
|
||||
setup: () => {},
|
||||
|
@ -3,9 +3,9 @@ import { describe, expect, it } from 'vitest'
|
||||
import { extractRouteRules } from '../src/pages/route-rules'
|
||||
|
||||
describe('route-rules', () => {
|
||||
it('should extract route rules from pages', async () => {
|
||||
it('should extract route rules from pages', () => {
|
||||
for (const [path, code] of Object.entries(examples)) {
|
||||
const result = await extractRouteRules(code, path)
|
||||
const result = extractRouteRules(code, path)
|
||||
|
||||
expect(result).toStrictEqual({
|
||||
'prerender': true,
|
||||
@ -33,7 +33,6 @@ defineRouteRules({
|
||||
`,
|
||||
// vue component with a normal script block, and defineRouteRules ambiently
|
||||
'component.vue': `
|
||||
|
||||
<script>
|
||||
defineRouteRules({
|
||||
prerender: true
|
||||
@ -43,14 +42,14 @@ export default {
|
||||
}
|
||||
</script>
|
||||
`,
|
||||
// TODO: JS component with defineRouteRules within a setup function
|
||||
// 'component.ts': `
|
||||
// export default {
|
||||
// setup() {
|
||||
// defineRouteRules({
|
||||
// prerender: true
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// `,
|
||||
// JS component with defineRouteRules within a setup function
|
||||
'component.ts': `
|
||||
export default {
|
||||
setup() {
|
||||
defineRouteRules({
|
||||
prerender: true
|
||||
})
|
||||
}
|
||||
}
|
||||
`,
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ import path from 'node:path'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import * as VueCompilerSFC from 'vue/compiler-sfc'
|
||||
import type { Plugin } from 'vite'
|
||||
import * as Parser from 'acorn'
|
||||
import type { Options } from '@vitejs/plugin-vue'
|
||||
import _vuePlugin from '@vitejs/plugin-vue'
|
||||
import { TreeShakeTemplatePlugin } from '../src/components/plugins/tree-shake'
|
||||
@ -56,14 +55,7 @@ const treeshakeTemplatePlugin = TreeShakeTemplatePlugin({
|
||||
|
||||
const treeshake = async (source: string): Promise<string> => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||
const result = await (treeshakeTemplatePlugin.transform! as Function).call({
|
||||
parse: (code: string, opts: any = {}) => Parser.parse(code, {
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
locations: true,
|
||||
...opts,
|
||||
}),
|
||||
}, source)
|
||||
const result = await (treeshakeTemplatePlugin.transform! as Function)(source)
|
||||
return typeof result === 'string' ? result : result?.code
|
||||
}
|
||||
|
||||
|
@ -305,9 +305,6 @@ importers:
|
||||
'@vue/shared':
|
||||
specifier: 3.5.13
|
||||
version: 3.5.13
|
||||
acorn:
|
||||
specifier: 8.14.0
|
||||
version: 8.14.0
|
||||
c12:
|
||||
specifier: 2.0.1
|
||||
version: 2.0.1(magicast@0.3.5)
|
||||
@ -392,6 +389,9 @@ importers:
|
||||
ohash:
|
||||
specifier: 1.1.4
|
||||
version: 1.1.4
|
||||
oxc-parser:
|
||||
specifier: ^0.38.0
|
||||
version: 0.38.0
|
||||
pathe:
|
||||
specifier: ^1.1.2
|
||||
version: 1.1.2
|
||||
@ -2191,6 +2191,49 @@ packages:
|
||||
'@one-ini/wasm@0.1.1':
|
||||
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
|
||||
|
||||
'@oxc-parser/binding-darwin-arm64@0.38.0':
|
||||
resolution: {integrity: sha512-yMDY/KrF2gEEpVIzaVWuO1savy303onvhg96a+1mUfLhgH9lvfZZyus4/LVokRHYCCy+6ey/1ytyilVnSeTDYA==}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxc-parser/binding-darwin-x64@0.38.0':
|
||||
resolution: {integrity: sha512-OD8PQT5nAdNCbmzMVfafIQi9/yxSvfEH5fpLXPKVTCtAEc/d5aX6JpipjW231/3TF8mjXO1y3xZM1xKGXJEk/A==}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-gnu@0.38.0':
|
||||
resolution: {integrity: sha512-REfFdTk+cdIC8etE8v0CoZtVObKIiymFsPkQTYca2V2ZwJ9/SgUr6NNNjLJdkGOipwjBk8d2cyOZzNDIMfzmqw==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-musl@0.38.0':
|
||||
resolution: {integrity: sha512-tSDRTahOoT4KDS0dicDEFgBH2nEDqNmqFG+N6PS2LrExYEDS01noRIxMFpx2Sz22a+6ZnvkfVmStp6VK+9fpBQ==}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-linux-x64-gnu@0.38.0':
|
||||
resolution: {integrity: sha512-qc6NdCzcCAxCK5KVde2ULq+7cyiJwrMV/1yozSUqvu26yme56Es3rWHFuPToxrhw+2olvc93AX+PVYMy3DqrGw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-linux-x64-musl@0.38.0':
|
||||
resolution: {integrity: sha512-x/9XyivlMjnQ7gofNK6u+L+BMdwKf/GuLJ0vrmrWolKGR9CBSzZRwZfTw+cG0T7U6Y6CN36tSqijA0eTo3U8zw==}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@oxc-parser/binding-win32-arm64-msvc@0.38.0':
|
||||
resolution: {integrity: sha512-SUlt+MUid0VUL5cLbbZzVGA9xNoqLl29xF1ueTeDt/BdQyrLELjTxoGtgisF6blAD6Rj2JqPtnfk+CT7GBwL2w==}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@oxc-parser/binding-win32-x64-msvc@0.38.0':
|
||||
resolution: {integrity: sha512-l/nFJutJ+zZTGj7ayL22r+og8g6dOC/47fSlsyl+KQXsmAFDStaARioHP9g+von/0bS23LX/9Eo8YeK5kFc7KA==}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@oxc-project/types@0.38.0':
|
||||
resolution: {integrity: sha512-WjRra3cmQt/VPRTwiVuYITm6RNr4SjwYeVZkT0oPn1M0Li2caILj1mlRELhHXad4nLAlnfliH5daHFKjQ9d3jQ==}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.0':
|
||||
resolution: {integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@ -2624,8 +2667,8 @@ packages:
|
||||
engines: {node: '>=8.10'}
|
||||
hasBin: true
|
||||
|
||||
'@stripe/stripe-js@4.8.0':
|
||||
resolution: {integrity: sha512-+4Cb0bVHlV4BJXxkJ3cCLSLuWxm3pXKtgcRacox146EuugjCzRRII5T5gUMgL4HpzrBLVwVxjKaZqntNWAXawQ==}
|
||||
'@stripe/stripe-js@4.9.0':
|
||||
resolution: {integrity: sha512-tMPZQZZXGWyNX7hbgenq+1xEj2oigJ54XddbtSX36VedoKsPBq7dxwRXu4Xd5FdpT3JDyyDtnmvYkaSnH1yHTQ==}
|
||||
engines: {node: '>=12.16'}
|
||||
|
||||
'@stylistic/eslint-plugin@2.11.0':
|
||||
@ -5915,6 +5958,9 @@ packages:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
||||
oxc-parser@0.38.0:
|
||||
resolution: {integrity: sha512-w/cUL64wDb72gaBoOnvodKgHhNF9pDjb2b8gPkDKJDTvIvlbcE9XGDT3cnXOP4N3XCMrRT4MC23bCHGb3gCFSQ==}
|
||||
|
||||
p-limit@2.3.0:
|
||||
resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==}
|
||||
engines: {node: '>=6'}
|
||||
@ -8758,7 +8804,7 @@ snapshots:
|
||||
'@nuxt/devtools-kit': 1.6.1(vite@6.0.1(@types/node@22.10.1)(jiti@2.4.0)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.1)(yaml@2.5.1))
|
||||
'@nuxt/devtools-ui-kit': 1.5.1(@nuxt/devtools@1.6.1(rollup@4.27.4)(vite@6.0.1(@types/node@22.10.1)(jiti@2.4.0)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.1)(yaml@2.5.1))(vue@3.5.13(typescript@5.6.3)))(@unocss/webpack@0.62.4(rollup@4.27.4)(webpack@5.96.1(esbuild@0.24.0)))(@vue/compiler-core@3.5.13)(change-case@5.4.4)(nuxt@packages+nuxt)(postcss@8.4.49)(rollup@4.27.4)(vite@6.0.1(@types/node@22.10.1)(jiti@2.4.0)(sass@1.78.0)(terser@5.32.0)(tsx@4.19.1)(yaml@2.5.1))(vue@3.5.13(typescript@5.6.3))(webpack@5.96.1(esbuild@0.24.0))
|
||||
'@nuxt/kit': link:packages/kit
|
||||
'@stripe/stripe-js': 4.8.0
|
||||
'@stripe/stripe-js': 4.9.0
|
||||
'@types/google.maps': 3.58.1
|
||||
'@types/vimeo__player': 2.18.3
|
||||
'@types/youtube': 0.1.0
|
||||
@ -8923,6 +8969,32 @@ snapshots:
|
||||
|
||||
'@one-ini/wasm@0.1.1': {}
|
||||
|
||||
'@oxc-parser/binding-darwin-arm64@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-darwin-x64@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-gnu@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-arm64-musl@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-x64-gnu@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-linux-x64-musl@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-arm64-msvc@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-parser/binding-win32-x64-msvc@0.38.0':
|
||||
optional: true
|
||||
|
||||
'@oxc-project/types@0.38.0': {}
|
||||
|
||||
'@parcel/watcher-android-arm64@2.5.0':
|
||||
optional: true
|
||||
|
||||
@ -9343,7 +9415,7 @@ snapshots:
|
||||
ignore: 5.3.2
|
||||
p-map: 4.0.0
|
||||
|
||||
'@stripe/stripe-js@4.8.0': {}
|
||||
'@stripe/stripe-js@4.9.0': {}
|
||||
|
||||
'@stylistic/eslint-plugin@2.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3)':
|
||||
dependencies:
|
||||
@ -13582,6 +13654,19 @@ snapshots:
|
||||
type-check: 0.4.0
|
||||
word-wrap: 1.2.5
|
||||
|
||||
oxc-parser@0.38.0:
|
||||
dependencies:
|
||||
'@oxc-project/types': 0.38.0
|
||||
optionalDependencies:
|
||||
'@oxc-parser/binding-darwin-arm64': 0.38.0
|
||||
'@oxc-parser/binding-darwin-x64': 0.38.0
|
||||
'@oxc-parser/binding-linux-arm64-gnu': 0.38.0
|
||||
'@oxc-parser/binding-linux-arm64-musl': 0.38.0
|
||||
'@oxc-parser/binding-linux-x64-gnu': 0.38.0
|
||||
'@oxc-parser/binding-linux-x64-musl': 0.38.0
|
||||
'@oxc-parser/binding-win32-arm64-msvc': 0.38.0
|
||||
'@oxc-parser/binding-win32-x64-msvc': 0.38.0
|
||||
|
||||
p-limit@2.3.0:
|
||||
dependencies:
|
||||
p-try: 2.2.0
|
||||
|
Loading…
Reference in New Issue
Block a user