Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(plugin-vue): multiple vue files using the same src file (fix #5925, #5447) #5994

Merged
merged 7 commits into from Dec 8, 2021
3 changes: 2 additions & 1 deletion packages/playground/vue/src-import/SrcImport.vue
@@ -1,3 +1,4 @@
<style src="/@/src-import/style.css" scoped></style>
<style src="/@/src-import/style2.css" scoped></style>
<template src="./template.html"></template>
<script src="./script.ts"></script>
<style src="/@/src-import/style.css" scoped></style>
6 changes: 6 additions & 0 deletions packages/playground/vue/src-import/script.ts
@@ -1,6 +1,12 @@
import { defineComponent } from 'vue'
import SrcImportStyle from './srcImportStyle.vue'
import SrcImportStyle2 from './srcImportStyle2.vue'

export default defineComponent({
components: {
SrcImportStyle,
SrcImportStyle2
},
setup() {
return {
msg: 'hello from script src!'
Expand Down
7 changes: 7 additions & 0 deletions packages/playground/vue/src-import/srcImportStyle.vue
@@ -0,0 +1,7 @@
<style src="/@/src-import/style.css" scoped></style>
<template>
<div class="src-imports-script">{{ msg }}</div>
</template>
<script setup>
const msg = 'hello from component A!'
</script>
4 changes: 4 additions & 0 deletions packages/playground/vue/src-import/srcImportStyle2.vue
@@ -0,0 +1,4 @@
<style src="/@/src-import/style2.css" scoped></style>
<template>
<div class="src-imports-style">This should be tan</div>
</template>
3 changes: 3 additions & 0 deletions packages/playground/vue/src-import/style2.css
@@ -0,0 +1,3 @@
.src-imports-script {
color: #0088ff;
}
2 changes: 2 additions & 0 deletions packages/playground/vue/src-import/template.html
@@ -1,3 +1,5 @@
<h2>SFC Src Imports</h2>
<div class="src-imports-script">{{ msg }}</div>
<div class="src-imports-style">This should be tan</div>
<SrcImportStyle></SrcImportStyle>
<SrcImportStyle2></SrcImportStyle2>
7 changes: 5 additions & 2 deletions packages/plugin-vue/src/index.ts
Expand Up @@ -9,7 +9,7 @@ import {
} from '@vue/compiler-sfc'
import { compiler } from './compiler'
import { parseVueRequest } from './utils/query'
import { getDescriptor } from './utils/descriptorCache'
import { getDescriptor, getSrcDescriptor } from './utils/descriptorCache'
import { getResolvedScript } from './script'
import { transformMain } from './main'
import { handleHotUpdate } from './handleHotUpdate'
Expand Down Expand Up @@ -223,7 +223,10 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
)
} else {
// sub block request
const descriptor = getDescriptor(filename, options)!
const descriptor = query.src
? getSrcDescriptor(filename, query)!
: getDescriptor(filename, options)!

if (query.type === 'template') {
return transformTemplateAsModule(code, descriptor, options, this, ssr)
} else if (query.type === 'style') {
Expand Down
10 changes: 5 additions & 5 deletions packages/plugin-vue/src/main.ts
Expand Up @@ -6,7 +6,7 @@ import { ResolvedOptions } from '.'
import {
createDescriptor,
getPrevDescriptor,
setDescriptor
setSrcDescriptor
} from './utils/descriptorCache'
import { PluginContext, SourceMap, TransformPluginContext } from 'rollup'
import { normalizePath } from '@rollup/pluginutils'
Expand Down Expand Up @@ -237,7 +237,7 @@ async function genTemplateCode(
await linkSrcToDescriptor(template.src, descriptor, pluginContext)
}
const src = template.src || descriptor.filename
const srcQuery = template.src ? `&src` : ``
const srcQuery = template.src ? `&src=${descriptor.id}` : ``
const attrsQuery = attrsToQuery(template.attrs, 'js', true)
const query = `?vue&type=template${srcQuery}${attrsQuery}`
const request = JSON.stringify(src + query)
Expand Down Expand Up @@ -279,7 +279,7 @@ async function genScriptCode(
const src = script.src || descriptor.filename
const langFallback = (script.src && path.extname(src).slice(1)) || 'js'
const attrsQuery = attrsToQuery(script.attrs, langFallback)
const srcQuery = script.src ? `&src` : ``
const srcQuery = script.src ? `&src=${descriptor.id}` : ``
const query = `?vue&type=script${srcQuery}${attrsQuery}`
const request = JSON.stringify(src + query)
scriptCode =
Expand Down Expand Up @@ -310,7 +310,7 @@ async function genStyleCode(
// do not include module in default query, since we use it to indicate
// that the module needs to export the modules json
const attrsQuery = attrsToQuery(style.attrs, 'css')
const srcQuery = style.src ? `&src` : ``
const srcQuery = style.src ? `&src=${descriptor.id}` : ``
const directQuery = asCustomElement ? `&inline` : ``
const query = `?vue&type=style&index=${i}${srcQuery}${directQuery}`
const styleRequest = src + query + attrsQuery
Expand Down Expand Up @@ -397,7 +397,7 @@ async function linkSrcToDescriptor(
(await pluginContext.resolve(src, descriptor.filename))?.id || src
// #1812 if the src points to a dep file, the resolved id may contain a
// version query.
setDescriptor(srcFile.replace(/\?.*$/, ''), descriptor)
setSrcDescriptor(srcFile.replace(/\?.*$/, ''), descriptor)
}

// these are built-in query parameters so should be ignored
Expand Down
15 changes: 12 additions & 3 deletions packages/plugin-vue/src/utils/descriptorCache.ts
Expand Up @@ -3,7 +3,7 @@ import path from 'path'
import slash from 'slash'
import hash from 'hash-sum'
import { CompilerError, SFCDescriptor } from '@vue/compiler-sfc'
import { ResolvedOptions } from '..'
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
Expand Down Expand Up @@ -66,6 +66,15 @@ export function getDescriptor(
}
}

export function setDescriptor(filename: string, entry: SFCDescriptor): void {
cache.set(filename, entry)
export function getSrcDescriptor(
filename: string,
query: VueQuery
): SFCDescriptor {
return cache.get(`${filename}?src=${query.src}`)!
}

export function setSrcDescriptor(filename: string, entry: SFCDescriptor): void {
// if multiple Vue files use the same src file, they will be overwritten
// should use other key
cache.set(`${filename}?src=${entry.id}`, entry)
}
5 changes: 1 addition & 4 deletions packages/plugin-vue/src/utils/query.ts
Expand Up @@ -2,7 +2,7 @@ import qs from 'querystring'

export interface VueQuery {
vue?: boolean
src?: boolean
src?: string
type?: 'script' | 'template' | 'style' | 'custom'
index?: number
lang?: string
Expand All @@ -18,9 +18,6 @@ export function parseVueRequest(id: string): {
if (query.vue != null) {
query.vue = true
}
if (query.src != null) {
query.src = true
}
if (query.index != null) {
query.index = Number(query.index)
}
Expand Down