Skip to content

Commit

Permalink
refactor(plugin-vue): resolve vue/compiler-sfc from project root
Browse files Browse the repository at this point in the history
BREAKING CHANGE: now requires vue@^3.2.13 as peer dep
  • Loading branch information
yyx990803 committed Dec 12, 2021
1 parent 5d6b0c0 commit b9171dd
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 51 deletions.
4 changes: 2 additions & 2 deletions packages/plugin-vue/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
},
"homepage": "https://github.com/vitejs/vite/tree/main/packages/plugin-vue#readme",
"peerDependencies": {
"vite": "^2.5.10"
"vite": "^2.5.10",
"vue": "^3.2.13"
},
"devDependencies": {
"@rollup/pluginutils": "^4.1.1",
"@types/hash-sum": "^1.0.0",
"@vue/compiler-sfc": "^3.2.23",
"debug": "^4.3.2",
"hash-sum": "^2.0.0",
"rollup": "^2.59.0",
Expand Down
29 changes: 17 additions & 12 deletions packages/plugin-vue/src/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
// extend the descriptor so we can store the scopeId on it
declare module '@vue/compiler-sfc' {
declare module 'vue/compiler-sfc' {
interface SFCDescriptor {
id: string
}
}

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

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

try {
// Vue 3.2.13+ ships the SFC compiler directly under the `vue` package
// making it no longer necessary to have @vue/compiler-sfc separately installed.
compiler = require('vue/compiler-sfc')
} catch (e) {
try {
compiler = require('@vue/compiler-sfc')
} catch (e) {
if (!compiler) {
throw new Error(
`@vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc ` +
`Failed to resolve vue/compiler-sfc.\n` +
`@vitejs/plugin-vue requires vue (>=3.2.13) or @vue/compiler-sfc ` +
`to be present in the dependency tree.`
)
}

return compiler
}

function tryRequire(id: string, from?: string) {
try {
return from ? require(require.resolve(id, { paths: [from] })) : require(id)
} catch (e) {}
}
2 changes: 1 addition & 1 deletion packages/plugin-vue/src/handleHotUpdate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import _debug from 'debug'
import { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc'
import { SFCBlock, SFCDescriptor } from 'vue/compiler-sfc'
import {
createDescriptor,
getDescriptor,
Expand Down
42 changes: 24 additions & 18 deletions packages/plugin-vue/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
SFCScriptCompileOptions,
SFCStyleCompileOptions,
SFCTemplateCompileOptions
} from '@vue/compiler-sfc'
import { compiler } from './compiler'
} from 'vue/compiler-sfc'
import * as _compiler from 'vue/compiler-sfc'
import { resolveCompiler } from './compiler'
import { parseVueRequest } from './utils/query'
import { getDescriptor, getSrcDescriptor } from './utils/descriptorCache'
import { getResolvedScript } from './script'
Expand All @@ -25,7 +26,7 @@ export interface Options {

isProduction?: boolean

// options to pass on to @vue/compiler-sfc
// options to pass on to vue/compiler-sfc
script?: Partial<SFCScriptCompileOptions>
template?: Partial<SFCTemplateCompileOptions>
style?: Partial<SFCStyleCompileOptions>
Expand Down Expand Up @@ -60,9 +61,15 @@ export interface Options {
* @deprecated the plugin now auto-detects whether it's being invoked for ssr.
*/
ssr?: boolean

/**
* Use custom compiler-sfc instance. Can be used to force a specific version.
*/
compiler?: typeof _compiler
}

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

// compat for older versions
const canUseRefTransform = typeof compiler.shouldTransformRef === 'function'

let options: ResolvedOptions = {
isProduction: process.env.NODE_ENV === 'production',
...rawOptions,
Expand All @@ -101,7 +105,8 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
customElement,
refTransform,
root: process.cwd(),
sourceMap: true
sourceMap: true,
compiler: null as any // to be set in configResolved
}

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

config(config) {
config() {
return {
define: {
__VUE_OPTIONS_API__: true,
Expand All @@ -139,7 +144,8 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
...options,
root: config.root,
sourceMap: config.command === 'build' ? !!config.build.sourcemap : true,
isProduction: config.isProduction
isProduction: config.isProduction,
compiler: options.compiler || resolveCompiler(config.root)
}
},

Expand Down Expand Up @@ -198,15 +204,15 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
return
}
if (!filter(filename) && !query.vue) {
if (!query.vue && refTransformFilter(filename)) {
if (!canUseRefTransform) {
this.warn('refTransform requires @vue/compiler-sfc@^3.2.5.')
} else if (compiler.shouldTransformRef(code)) {
return compiler.transformRef(code, {
filename,
sourceMap: true
})
}
if (
!query.vue &&
refTransformFilter(filename) &&
options.compiler.shouldTransformRef(code)
) {
return options.compiler.transformRef(code, {
filename,
sourceMap: true
})
}
return
}
Expand Down
5 changes: 2 additions & 3 deletions packages/plugin-vue/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import qs from 'querystring'
import path from 'path'
import { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc'
import { compiler } from './compiler'
import { SFCBlock, SFCDescriptor } from 'vue/compiler-sfc'
import { ResolvedOptions } from '.'
import {
createDescriptor,
Expand Down Expand Up @@ -266,7 +265,7 @@ async function genScriptCode(
// If the script is js/ts and has no external src, it can be directly placed
// in the main module.
if ((!script.lang || script.lang === 'ts') && !script.src) {
scriptCode = compiler.rewriteDefault(
scriptCode = options.compiler.rewriteDefault(
script.content,
'_sfc_main',
script.lang === 'ts' ? ['typescript'] : undefined
Expand Down
5 changes: 2 additions & 3 deletions packages/plugin-vue/src/script.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { SFCDescriptor, SFCScriptBlock } from '@vue/compiler-sfc'
import { SFCDescriptor, SFCScriptBlock } from 'vue/compiler-sfc'
import { ResolvedOptions } from '.'
import { resolveTemplateCompilerOptions } from './template'
import { compiler } from './compiler'

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

let resolved: SFCScriptBlock | null = null

resolved = compiler.compileScript(descriptor, {
resolved = options.compiler.compileScript(descriptor, {
...options.script,
id: descriptor.id,
isProd: options.isProduction,
Expand Down
5 changes: 2 additions & 3 deletions packages/plugin-vue/src/style.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { SFCDescriptor } from '@vue/compiler-sfc'
import { SFCDescriptor } from 'vue/compiler-sfc'
import { TransformPluginContext } from 'rollup'
import { ResolvedOptions } from '.'
import { compiler } from './compiler'

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function transformStyle(
Expand All @@ -14,7 +13,7 @@ export async function transformStyle(
const block = descriptor.styles[index]
// vite already handles pre-processors and CSS module so this is only
// applying SFC-specific transforms like scoped mode and CSS vars rewrite (v-bind(var))
const result = await compiler.compileStyleAsync({
const result = await options.compiler.compileStyleAsync({
...options.style,
filename: descriptor.filename,
id: `data-v-${descriptor.id}`,
Expand Down
7 changes: 3 additions & 4 deletions packages/plugin-vue/src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { PluginContext, TransformPluginContext } from 'rollup'
import { ResolvedOptions } from '.'
import { getResolvedScript } from './script'
import { createRollupError } from './utils/error'
import { compiler } from './compiler'

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export async function transformTemplateAsModule(
Expand Down Expand Up @@ -70,7 +69,7 @@ export function compile(
ssr: boolean
) {
const filename = descriptor.filename
const result = compiler.compileTemplate({
const result = options.compiler.compileTemplate({
...resolveTemplateCompilerOptions(descriptor, options, ssr)!,
source: code
})
Expand Down Expand Up @@ -111,10 +110,10 @@ export function resolveTemplateCompilerOptions(
const { id, filename, cssVars } = descriptor

let transformAssetUrls = options.template?.transformAssetUrls
// @vue/compiler-sfc/dist/compiler-sfc.d.ts should export `AssetURLOptions`
// compiler-sfc should export `AssetURLOptions`
let assetUrlOptions //: AssetURLOptions | undefined
if (options.devServer) {
// during dev, inject vite base so that @vue/compiler-sfc can transform
// during dev, inject vite base so that compiler-sfc can transform
// relative paths directly to absolute paths without incurring an extra import
// request
if (filename.startsWith(options.root)) {
Expand Down
7 changes: 3 additions & 4 deletions packages/plugin-vue/src/utils/descriptorCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import fs from 'fs'
import path from 'path'
import slash from 'slash'
import hash from 'hash-sum'
import { CompilerError, SFCDescriptor } from '@vue/compiler-sfc'
import { CompilerError, SFCDescriptor } from 'vue/compiler-sfc'
import { ResolvedOptions, VueQuery } from '..'
import { compiler } from '../compiler'

// node_modules/@vue/compiler-sfc/dist/compiler-sfc.d.ts SFCParseResult should be exported so it can be re-used
// compiler-sfc should be exported so it can be re-used
export interface SFCParseResult {
descriptor: SFCDescriptor
errors: Array<CompilerError | SyntaxError>
Expand All @@ -18,7 +17,7 @@ const prevCache = new Map<string, SFCDescriptor | undefined>()
export function createDescriptor(
filename: string,
source: string,
{ root, isProduction, sourceMap }: ResolvedOptions
{ root, isProduction, sourceMap, compiler }: ResolvedOptions
): SFCParseResult {
const { descriptor, errors } = compiler.parse(source, {
filename,
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-vue/src/utils/error.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CompilerError } from '@vue/compiler-sfc'
import { CompilerError } from 'vue/compiler-sfc'
import { RollupError } from 'rollup'

export function createRollupError(
Expand Down

0 comments on commit b9171dd

Please sign in to comment.