Skip to content

Commit ce8b0fe

Browse files
committedDec 12, 2021
refactor(plugin-vue): resolve vue/compiler-sfc from project root
BREAKING CHANGE: now requires vue@^3.2.13 as peer dep
1 parent d4c5cff commit ce8b0fe

11 files changed

+57
-53
lines changed
 

‎packages/plugin-vue/package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
},
3232
"homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-vue#readme",
3333
"peerDependencies": {
34-
"vite": "^2.5.10"
34+
"vite": "^2.5.10",
35+
"vue": "^3.2.13"
3536
},
3637
"devDependencies": {
3738
"@rollup/pluginutils": "^4.1.1",
3839
"@types/hash-sum": "^1.0.0",
39-
"@vue/compiler-sfc": "^3.2.23",
4040
"debug": "^4.3.2",
4141
"hash-sum": "^2.0.0",
4242
"rollup": "^2.59.0",

‎packages/plugin-vue/src/compiler.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
// extend the descriptor so we can store the scopeId on it
2-
declare module '@vue/compiler-sfc' {
2+
declare module 'vue/compiler-sfc' {
33
interface SFCDescriptor {
44
id: string
55
}
66
}
77

8-
import * as _compiler from '@vue/compiler-sfc'
8+
import * as _compiler from 'vue/compiler-sfc'
99

10-
export let compiler: typeof _compiler
10+
export function resolveCompiler(root: string): typeof _compiler {
11+
// resolve from project root first, then fallback to peer dep (if any)
12+
const compiler =
13+
tryRequire('vue/compiler-sfc', root) || tryRequire('vue/compiler-sfc')
1114

12-
try {
13-
// Vue 3.2.13+ ships the SFC compiler directly under the `vue` package
14-
// making it no longer necessary to have @vue/compiler-sfc separately installed.
15-
compiler = require('vue/compiler-sfc')
16-
} catch (e) {
17-
try {
18-
compiler = require('@vue/compiler-sfc')
19-
} catch (e) {
15+
if (!compiler) {
2016
throw new Error(
21-
`@vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc ` +
17+
`Failed to resolve vue/compiler-sfc.\n` +
18+
`@vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc ` +
2219
`to be present in the dependency tree.`
2320
)
2421
}
22+
23+
return compiler
24+
}
25+
26+
function tryRequire(id: string, from?: string) {
27+
try {
28+
return from ? require(require.resolve(id, { paths: [from] })) : require(id)
29+
} catch (e) {}
2530
}

‎packages/plugin-vue/src/handleHotUpdate.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import _debug from 'debug'
2-
import { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc'
2+
import { SFCBlock, SFCDescriptor } from 'vue/compiler-sfc'
33
import {
44
createDescriptor,
55
getDescriptor,

‎packages/plugin-vue/src/index.ts

+24-18
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import {
66
SFCScriptCompileOptions,
77
SFCStyleCompileOptions,
88
SFCTemplateCompileOptions
9-
} from '@vue/compiler-sfc'
10-
import { compiler } from './compiler'
9+
} from 'vue/compiler-sfc'
10+
import * as _compiler from 'vue/compiler-sfc'
11+
import { resolveCompiler } from './compiler'
1112
import { parseVueRequest } from './utils/query'
1213
import { getDescriptor, getSrcDescriptor } from './utils/descriptorCache'
1314
import { getResolvedScript } from './script'
@@ -25,7 +26,7 @@ export interface Options {
2526

2627
isProduction?: boolean
2728

28-
// options to pass on to @vue/compiler-sfc
29+
// options to pass on to vue/compiler-sfc
2930
script?: Partial<SFCScriptCompileOptions>
3031
template?: Partial<SFCTemplateCompileOptions>
3132
style?: Partial<SFCStyleCompileOptions>
@@ -60,9 +61,15 @@ export interface Options {
6061
* @deprecated the plugin now auto-detects whether it's being invoked for ssr.
6162
*/
6263
ssr?: boolean
64+
65+
/**
66+
* Use custom compiler-sfc instance. Can be used to force a specific version.
67+
*/
68+
compiler?: typeof _compiler
6369
}
6470

6571
export interface ResolvedOptions extends Options {
72+
compiler: typeof _compiler
6673
root: string
6774
sourceMap: boolean
6875
devServer?: ViteDevServer
@@ -90,9 +97,6 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
9097
? createFilter(/\.(j|t)sx?$/, /node_modules/)
9198
: createFilter(refTransform)
9299

93-
// compat for older versions
94-
const canUseRefTransform = typeof compiler.shouldTransformRef === 'function'
95-
96100
let options: ResolvedOptions = {
97101
isProduction: process.env.NODE_ENV === 'production',
98102
...rawOptions,
@@ -101,7 +105,8 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
101105
customElement,
102106
refTransform,
103107
root: process.cwd(),
104-
sourceMap: true
108+
sourceMap: true,
109+
compiler: null as any // to be set in configResolved
105110
}
106111

107112
// Temporal handling for 2.7 breaking change
@@ -122,7 +127,7 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
122127
return handleHotUpdate(ctx, options)
123128
},
124129

125-
config(config) {
130+
config() {
126131
return {
127132
define: {
128133
__VUE_OPTIONS_API__: true,
@@ -139,7 +144,8 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
139144
...options,
140145
root: config.root,
141146
sourceMap: config.command === 'build' ? !!config.build.sourcemap : true,
142-
isProduction: config.isProduction
147+
isProduction: config.isProduction,
148+
compiler: options.compiler || resolveCompiler(config.root)
143149
}
144150
},
145151

@@ -198,15 +204,15 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
198204
return
199205
}
200206
if (!filter(filename) && !query.vue) {
201-
if (!query.vue && refTransformFilter(filename)) {
202-
if (!canUseRefTransform) {
203-
this.warn('refTransform requires @vue/compiler-sfc@^3.2.5.')
204-
} else if (compiler.shouldTransformRef(code)) {
205-
return compiler.transformRef(code, {
206-
filename,
207-
sourceMap: true
208-
})
209-
}
207+
if (
208+
!query.vue &&
209+
refTransformFilter(filename) &&
210+
options.compiler.shouldTransformRef(code)
211+
) {
212+
return options.compiler.transformRef(code, {
213+
filename,
214+
sourceMap: true
215+
})
210216
}
211217
return
212218
}

‎packages/plugin-vue/src/main.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import qs from 'querystring'
22
import path from 'path'
3-
import { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc'
4-
import { compiler } from './compiler'
3+
import { SFCBlock, SFCDescriptor } from 'vue/compiler-sfc'
54
import { ResolvedOptions } from '.'
65
import {
76
createDescriptor,
@@ -266,7 +265,7 @@ async function genScriptCode(
266265
// If the script is js/ts and has no external src, it can be directly placed
267266
// in the main module.
268267
if ((!script.lang || script.lang === 'ts') && !script.src) {
269-
scriptCode = compiler.rewriteDefault(
268+
scriptCode = options.compiler.rewriteDefault(
270269
script.content,
271270
'_sfc_main',
272271
script.lang === 'ts' ? ['typescript'] : undefined

‎packages/plugin-vue/src/script.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { SFCDescriptor, SFCScriptBlock } from '@vue/compiler-sfc'
1+
import { SFCDescriptor, SFCScriptBlock } from 'vue/compiler-sfc'
22
import { ResolvedOptions } from '.'
33
import { resolveTemplateCompilerOptions } from './template'
4-
import { compiler } from './compiler'
54

65
// ssr and non ssr builds would output different script content
76
const clientCache = new WeakMap<SFCDescriptor, SFCScriptBlock | null>()
@@ -49,7 +48,7 @@ export function resolveScript(
4948

5049
let resolved: SFCScriptBlock | null = null
5150

52-
resolved = compiler.compileScript(descriptor, {
51+
resolved = options.compiler.compileScript(descriptor, {
5352
...options.script,
5453
id: descriptor.id,
5554
isProd: options.isProduction,

‎packages/plugin-vue/src/style.ts

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { SFCDescriptor } from '@vue/compiler-sfc'
1+
import { SFCDescriptor } from 'vue/compiler-sfc'
22
import { TransformPluginContext } from 'rollup'
33
import { ResolvedOptions } from '.'
4-
import { compiler } from './compiler'
54

65
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
76
export async function transformStyle(
@@ -14,7 +13,7 @@ export async function transformStyle(
1413
const block = descriptor.styles[index]
1514
// vite already handles pre-processors and CSS module so this is only
1615
// applying SFC-specific transforms like scoped mode and CSS vars rewrite (v-bind(var))
17-
const result = await compiler.compileStyleAsync({
16+
const result = await options.compiler.compileStyleAsync({
1817
...options.style,
1918
filename: descriptor.filename,
2019
id: `data-v-${descriptor.id}`,

‎packages/plugin-vue/src/template.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { PluginContext, TransformPluginContext } from 'rollup'
1010
import { ResolvedOptions } from '.'
1111
import { getResolvedScript } from './script'
1212
import { createRollupError } from './utils/error'
13-
import { compiler } from './compiler'
1413

1514
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
1615
export async function transformTemplateAsModule(
@@ -70,7 +69,7 @@ export function compile(
7069
ssr: boolean
7170
) {
7271
const filename = descriptor.filename
73-
const result = compiler.compileTemplate({
72+
const result = options.compiler.compileTemplate({
7473
...resolveTemplateCompilerOptions(descriptor, options, ssr)!,
7574
source: code
7675
})
@@ -111,10 +110,10 @@ export function resolveTemplateCompilerOptions(
111110
const { id, filename, cssVars } = descriptor
112111

113112
let transformAssetUrls = options.template?.transformAssetUrls
114-
// @vue/compiler-sfc/dist/compiler-sfc.d.ts should export `AssetURLOptions`
113+
// compiler-sfc should export `AssetURLOptions`
115114
let assetUrlOptions //: AssetURLOptions | undefined
116115
if (options.devServer) {
117-
// during dev, inject vite base so that @vue/compiler-sfc can transform
116+
// during dev, inject vite base so that compiler-sfc can transform
118117
// relative paths directly to absolute paths without incurring an extra import
119118
// request
120119
if (filename.startsWith(options.root)) {

‎packages/plugin-vue/src/utils/descriptorCache.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@ import fs from 'fs'
22
import path from 'path'
33
import slash from 'slash'
44
import hash from 'hash-sum'
5-
import { CompilerError, SFCDescriptor } from '@vue/compiler-sfc'
5+
import { CompilerError, SFCDescriptor } from 'vue/compiler-sfc'
66
import { ResolvedOptions, VueQuery } from '..'
7-
import { compiler } from '../compiler'
87

9-
// node_modules/@vue/compiler-sfc/dist/compiler-sfc.d.ts SFCParseResult should be exported so it can be re-used
8+
// compiler-sfc should be exported so it can be re-used
109
export interface SFCParseResult {
1110
descriptor: SFCDescriptor
1211
errors: Array<CompilerError | SyntaxError>
@@ -18,7 +17,7 @@ const prevCache = new Map<string, SFCDescriptor | undefined>()
1817
export function createDescriptor(
1918
filename: string,
2019
source: string,
21-
{ root, isProduction, sourceMap }: ResolvedOptions
20+
{ root, isProduction, sourceMap, compiler }: ResolvedOptions
2221
): SFCParseResult {
2322
const { descriptor, errors } = compiler.parse(source, {
2423
filename,

‎packages/plugin-vue/src/utils/error.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CompilerError } from '@vue/compiler-sfc'
1+
import { CompilerError } from 'vue/compiler-sfc'
22
import { RollupError } from 'rollup'
33

44
export function createRollupError(

‎pnpm-lock.yaml

-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.