diff --git a/packages/plugin-vue/src/index.ts b/packages/plugin-vue/src/index.ts index 4f42b717..220a6356 100644 --- a/packages/plugin-vue/src/index.ts +++ b/packages/plugin-vue/src/index.ts @@ -17,7 +17,7 @@ import { SFCTemplateCompileOptions } from '@vue/compiler-sfc' import { parseVueRequest } from './utils/query' -import { getDescriptor, setDescriptor } from './utils/descriptorCache' +import { getDescriptor } from './utils/descriptorCache' import { getResolvedScript } from './script' import { transformMain } from './main' import { handleHotUpdate } from './handleHotUpdate' @@ -90,34 +90,15 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin { }, async resolveId(id, importer) { - const { filename, query } = parseVueRequest(id) // serve subpart requests (*?vue) as virtual modules - if (query.vue) { - if (query.src) { - const resolved = await this.resolve(filename, importer, { - skipSelf: true - }) - if (resolved) { - // associate this imported file to the importer SFC's descriptor - // so that we can retrieve it in transform() - setDescriptor(resolved.id, getDescriptor(importer!)) - const [, originalQuery] = id.split('?', 2) - resolved.id += `?${originalQuery}` - return resolved - } - } else if (!filter(filename)) { - return null - } + if (parseVueRequest(id).query.vue) { return id } }, load(id) { const { filename, query } = parseVueRequest(id) - if (!filter(filename)) { - return - } - // serve subpart virtual modules + // select corresponding block for subpart virtual modules if (query.vue) { if (query.src) { return fs.readFileSync(filename, 'utf-8') @@ -145,16 +126,15 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin { transform(code, id) { const { filename, query } = parseVueRequest(id) - if (!filter(filename)) { + if (!query.vue && !filter(filename)) { return } if (!query.vue) { // main request return transformMain(code, filename, options, this) - } - - if (query.vue) { + } else { + // sub block request const descriptor = getDescriptor(filename) if (query.type === 'template') { return transformTemplateAsModule(code, descriptor, options, this) diff --git a/packages/plugin-vue/src/main.ts b/packages/plugin-vue/src/main.ts index 1478aa7b..cb4f2876 100644 --- a/packages/plugin-vue/src/main.ts +++ b/packages/plugin-vue/src/main.ts @@ -1,7 +1,12 @@ import qs from 'querystring' +import path from 'path' import { rewriteDefault, SFCBlock, SFCDescriptor } from '@vue/compiler-sfc' import { ResolvedOptions } from '.' -import { createDescriptor, getPrevDescriptor } from './utils/descriptorCache' +import { + createDescriptor, + getPrevDescriptor, + setDescriptor +} from './utils/descriptorCache' import { PluginContext, TransformPluginContext } from 'rollup' import { resolveScript } from './script' import { transformTemplateInMain } from './template' @@ -162,14 +167,16 @@ function genTemplateCode( pluginContext ) } else { + if (template.src) { + linkSrcToDescriptor(template.src, descriptor) + } const src = template.src || descriptor.filename const srcQuery = template.src ? `&src` : `` const attrsQuery = attrsToQuery(template.attrs, 'js', true) const query = `?vue&type=template${srcQuery}${attrsQuery}` + const request = JSON.stringify(src + query) return { - code: `import { ${renderFnName} as _sfc_${renderFnName} } from ${JSON.stringify( - src + query - )}`, + code: `import { ${renderFnName} as _sfc_${renderFnName} } from ${request}`, map: undefined } } @@ -205,14 +212,17 @@ async function genScriptCode( map = result.map } } else { + if (script.src) { + linkSrcToDescriptor(script.src, descriptor) + } const src = script.src || descriptor.filename - const attrsQuery = attrsToQuery(script.attrs, 'js') + const langFallback = (script.src && path.extname(src).slice(1)) || 'js' + const attrsQuery = attrsToQuery(script.attrs, langFallback) const srcQuery = script.src ? `&src` : `` const query = `?vue&type=script${srcQuery}${attrsQuery}` - const scriptRequest = JSON.stringify(src + query) + const request = JSON.stringify(src + query) scriptCode = - `import _sfc_main from ${scriptRequest}\n` + - `export * from ${scriptRequest}` // support named exports + `import _sfc_main from ${request}\n` + `export * from ${request}` // support named exports } } return { @@ -226,6 +236,9 @@ function genStyleCode(descriptor: SFCDescriptor) { let hasCSSModules = false if (descriptor.styles.length) { descriptor.styles.forEach((style, i) => { + if (style.src) { + linkSrcToDescriptor(style.src, descriptor) + } const src = style.src || descriptor.filename // do not include module in default query, since we use it to indicate // that the module needs to export the modules json @@ -251,6 +264,9 @@ function genStyleCode(descriptor: SFCDescriptor) { function genCustomBlockCode(descriptor: SFCDescriptor) { let code = '' descriptor.customBlocks.forEach((block, index) => { + if (block.src) { + linkSrcToDescriptor(block.src, descriptor) + } const src = block.src || descriptor.filename const attrsQuery = attrsToQuery(block.attrs, block.type) const srcQuery = block.src ? `&src` : `` @@ -277,6 +293,19 @@ function genCSSModulesCode( ) } +/** + * For blocks with src imports, it is important to link the imported file + * with its owner SFC descriptor so that we can get the information about + * the owner SFC when compiling that file in the transform phase. + */ +function linkSrcToDescriptor(src: string, descriptor: SFCDescriptor) { + const srcFile = path.posix.resolve( + path.posix.dirname(descriptor.filename), + src + ) + setDescriptor(srcFile, descriptor) +} + // these are built-in query parameters so should be ignored // if the user happen to add them as attrs const ignoreList = ['id', 'index', 'src', 'type', 'lang', 'module'] diff --git a/packages/plugin-vue/src/utils/query.ts b/packages/plugin-vue/src/utils/query.ts index 51a5f654..25702eaf 100644 --- a/packages/plugin-vue/src/utils/query.ts +++ b/packages/plugin-vue/src/utils/query.ts @@ -2,8 +2,8 @@ import qs from 'querystring' export interface VueQuery { vue?: boolean + src?: boolean type?: 'script' | 'template' | 'style' | 'custom' - src?: string index?: number lang?: string } @@ -14,6 +14,9 @@ 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) }