Skip to content

Commit ffe7dc5

Browse files
committed
feat: support directives
close #155
1 parent 669be0b commit ffe7dc5

File tree

11 files changed

+391
-129
lines changed

11 files changed

+391
-129
lines changed

package.json

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
"description": "Components auto importing for Vue",
55
"homepage": "https://github.com/antfu/unplugin-vue-components",
66
"bugs": "https://github.com/antfu/unplugin-vue-components/issues",
7+
"license": "MIT",
78
"repository": {
89
"type": "git",
910
"url": "https://github.com/antfu/unplugin-vue-components"
1011
},
1112
"funding": "https://github.com/sponsors/antfu",
12-
"license": "MIT",
1313
"author": "antfu <[email protected]>",
14+
"files": [
15+
"dist",
16+
"*.d.ts"
17+
],
1418
"exports": {
1519
".": {
1620
"require": "./dist/index.js",
@@ -45,10 +49,6 @@
4549
"main": "dist/index.js",
4650
"module": "dist/index.mjs",
4751
"types": "index.d.ts",
48-
"files": [
49-
"dist",
50-
"*.d.ts"
51-
],
5252
"scripts": {
5353
"build": "rimraf dist && tsup src/*.ts --format cjs,esm --dts --splitting && esno scripts/postbuild.ts",
5454
"dev": "tsup src/*.ts --format cjs,esm --watch src",
@@ -59,6 +59,9 @@
5959
"test": "jest",
6060
"test:update": "jest --u"
6161
},
62+
"peerDependencies": {
63+
"vue": "2 || 3"
64+
},
6265
"dependencies": {
6366
"@antfu/utils": "^0.3.0",
6467
"@rollup/pluginutils": "^4.1.1",
@@ -73,6 +76,9 @@
7376
},
7477
"devDependencies": {
7578
"@antfu/eslint-config": "^0.9.0",
79+
"@babel/parser": "^7.15.8",
80+
"@babel/traverse": "^7.15.4",
81+
"@babel/types": "^7.15.6",
7682
"@types/debug": "^4.1.7",
7783
"@types/jest": "^27.0.2",
7884
"@types/minimatch": "^3.0.5",
@@ -90,9 +96,6 @@
9096
"typescript": "^4.4.3",
9197
"vite": "^2.5.10"
9298
},
93-
"peerDependencies": {
94-
"vue": "2 || 3"
95-
},
9699
"engines": {
97100
"node": ">=14"
98101
}

pnpm-lock.yaml

Lines changed: 85 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/core/context.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ import { pascalCase, getNameFromFilePath, resolveAlias, matchGlobs, parseId } fr
88
import { resolveOptions } from './options'
99
import { searchComponents } from './fs/glob'
1010
import { generateDeclaration } from './declaration'
11-
import { Vue2Transformer } from './transforms/vue2'
12-
import { Vue3Transformer } from './transforms/vue3'
11+
import transformer from './transformer'
1312

1413
const debug = {
1514
components: Debug('unplugin-vue-components:context:components'),
@@ -51,9 +50,7 @@ export class Context {
5150

5251
setTransformer(name: Options['transformer']) {
5352
debug.env('transformer', name)
54-
this.transformer = name === 'vue2'
55-
? Vue2Transformer(this)
56-
: Vue3Transformer(this)
53+
this.transformer = transformer(this, name || 'vue3')
5754
}
5855

5956
transform(code: string, id: string) {
@@ -181,15 +178,15 @@ export class Context {
181178
})
182179
}
183180

184-
async findComponent(name: string, excludePaths: string[] = [], rawName?: string): Promise<ComponentInfo | undefined> {
181+
async findComponent(name: string, type: 'component' | 'directive', excludePaths: string[] = []): Promise<ComponentInfo | undefined> {
185182
// resolve from fs
186183
let info = this._componentNameMap[name]
187184
if (info && !excludePaths.includes(info.path) && !excludePaths.includes(info.path.slice(1)))
188185
return info
189186

190187
// custom resolvers
191188
for (const resolver of this.options.resolvers) {
192-
const result = await resolver(name)
189+
const result = await resolver(name, type)
193190
if (result) {
194191
if (typeof result === 'string') {
195192
info = {

src/core/transformer.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import Debug from 'debug'
2+
import MagicString from 'magic-string'
3+
import { TransformResult } from 'unplugin'
4+
import { CallExpression } from '@babel/types'
5+
import { parse } from '@babel/parser'
6+
import traverse from '@babel/traverse'
7+
import type { Transformer } from '../types'
8+
import { DISABLE_COMMENT } from './constants'
9+
import { Context } from './context'
10+
import transformComponent from './transforms/component'
11+
import transformDirectives from './transforms/directive'
12+
13+
const debug = Debug('unplugin-vue-components:transform:vue2')
14+
15+
export default (ctx: Context, version: 'vue2'|'vue3'): Transformer => {
16+
return async(code, id, path) => {
17+
ctx.searchGlob()
18+
19+
const sfcPath = ctx.normalizePath(path)
20+
debug(sfcPath)
21+
22+
const s = new MagicString(code)
23+
const ast = parse(code, {
24+
sourceType: 'module',
25+
})
26+
const nodes: CallExpression[] = []
27+
traverse(ast, {
28+
CallExpression(path) {
29+
nodes.push(path.node)
30+
},
31+
})
32+
33+
await transformComponent(nodes, version, s, ctx, sfcPath)
34+
await transformDirectives(nodes, version, s, ctx, sfcPath, ast)
35+
36+
s.prepend(DISABLE_COMMENT)
37+
38+
const result: TransformResult = { code: s.toString() }
39+
if (ctx.sourcemap)
40+
result.map = s.generateMap({ source: id, includeContent: true })
41+
return result
42+
}
43+
}

src/core/transforms/component.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import Debug from 'debug'
2+
import type { CallExpression } from '@babel/types'
3+
import type MagicString from 'magic-string'
4+
import { pascalCase, stringifyComponentImport } from '../utils'
5+
import type { Context } from '../context'
6+
7+
const debug = Debug('unplugin-vue-components:transform:component')
8+
9+
export default async(nodes: CallExpression[], version: 'vue2' | 'vue3', s: MagicString, ctx: Context, sfcPath: string) => {
10+
let no = 0
11+
12+
for (const node of nodes) {
13+
const { callee, arguments: args } = node
14+
if (callee.type !== 'Identifier' || callee.name !== (version === 'vue2' ? '_c' : '_resolveComponent') || args[0].type !== 'StringLiteral')
15+
continue
16+
const componentName = args[0].value
17+
if (!componentName || componentName.startsWith('_'))
18+
continue
19+
20+
debug(`| ${componentName}`)
21+
const name = pascalCase(componentName)
22+
ctx.updateUsageMap(sfcPath, [name])
23+
24+
const component = await ctx.findComponent(name, 'component', [sfcPath])
25+
if (component) {
26+
const var_name = `__unplugin_components_${no}`
27+
s.prepend(`${stringifyComponentImport({ ...component, name: var_name }, ctx)};\n`)
28+
no += 1
29+
30+
const replacedNode = version === 'vue2' ? args[0] : node
31+
s.overwrite(replacedNode.start!, replacedNode.end!, var_name)
32+
}
33+
}
34+
35+
debug(`^ (${no})`)
36+
}

0 commit comments

Comments
 (0)