Skip to content
This repository has been archived by the owner on Jan 18, 2022. It is now read-only.

Commit

Permalink
feat: new script setup compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Nov 19, 2020
1 parent ea6d63f commit d1a528f
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 113 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@types/debug": "^4.1.5",
"@types/jest": "^25.2.3",
"@types/node": "^13.13.2",
"@vue/compiler-sfc": "^3.0.0-rc.5",
"@vue/compiler-sfc": "^3.0.2",
"husky": "^4.2.0",
"jest": "^26.0.1",
"lint-staged": "^10.1.7",
Expand Down
10 changes: 5 additions & 5 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ describe('Rollup Plugin Vue', () => {
const { code } = await transform(`<style>.foo {}</style>`, `example.vue`)
expect(code).toEqual(
expect.stringContaining(
`import "example.vue?vue&type=style&index=0&lang.css"`
`import "example.vue?vue&type=style&index=0&id=063a7d4c&lang.css"`
)
)
})
Expand All @@ -100,12 +100,12 @@ describe('Rollup Plugin Vue', () => {
)
expect(code).toEqual(
expect.stringContaining(
`import "example.vue?vue&type=style&index=0&lang.css`
`import "example.vue?vue&type=style&index=0&id=063a7d4c&lang.css`
)
)
expect(code).toEqual(
expect.stringContaining(
`import style0 from "example.vue?vue&type=style&index=0&module=true&lang.css`
`import style0 from "example.vue?vue&type=style&index=0&id=063a7d4c&module=true&lang.css`
)
)
expect(code).toEqual(expect.stringContaining('script.__cssModules = {}'))
Expand All @@ -121,12 +121,12 @@ describe('Rollup Plugin Vue', () => {
)
expect(code).toEqual(
expect.stringContaining(
`import "example.vue?vue&type=style&index=0&lang.css`
`import "example.vue?vue&type=style&index=0&id=063a7d4c&lang.css`
)
)
expect(code).toEqual(
expect.stringContaining(
`import style0 from "example.vue?vue&type=style&index=0&module=custom&lang.css`
`import style0 from "example.vue?vue&type=style&index=0&id=063a7d4c&module=custom&lang.css`
)
)
expect(code).toEqual(expect.stringContaining('script.__cssModules = {}'))
Expand Down
145 changes: 96 additions & 49 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
SFCTemplateCompileOptions,
SFCTemplateCompileResults,
SFCAsyncStyleCompileOptions,
generateCssVars,
} from '@vue/compiler-sfc'
import fs from 'fs'
import createDebugger from 'debug'
Expand Down Expand Up @@ -117,7 +118,7 @@ export default function PluginVue(userOptions: Partial<Options> = {}): Plugin {
query.type === 'template'
? descriptor.template!
: query.type === 'script'
? descriptor.script!
? descriptor.scriptCompiled || descriptor.script
: query.type === 'style'
? descriptor.styles[query.index]
: typeof query.index === 'number'
Expand All @@ -142,36 +143,16 @@ export default function PluginVue(userOptions: Partial<Options> = {}): Plugin {
if (!query.src && !filter(query.filename)) return null

const descriptor = getDescriptor(query.filename)
const hasScoped = descriptor.styles.some((s) => s.scoped)
if (query.src) {
this.addWatchFile(query.filename)
}

if (query.type === 'template') {
debug(`transform(${id})`)
const block = descriptor.template!
const preprocessLang = block.lang
const preprocessOptions =
preprocessLang &&
options.templatePreprocessOptions &&
options.templatePreprocessOptions[preprocessLang]
const result = compileTemplate({
filename: query.filename,
...getTemplateCompilerOptions(options, descriptor, query.id),
source: code,
inMap: query.src ? undefined : block.map,
preprocessLang,
preprocessOptions,
preprocessCustomRequire: options.preprocessCustomRequire,
compiler: options.compiler,
ssr: isServer,
compilerOptions: {
...options.compilerOptions,
scopeId: hasScoped ? `data-v-${query.id}` : undefined,
bindingMetadata: descriptor.script
? descriptor.script.bindings
: undefined,
},
transformAssetUrls: options.transformAssetUrls,
filename: query.filename,
})

if (result.errors.length) {
Expand Down Expand Up @@ -232,10 +213,10 @@ export default function PluginVue(userOptions: Partial<Options> = {}): Plugin {

const result = await compileStyleAsync({
filename: query.filename,
id: `data-v-${query.id!}`,
id: `data-v-${query.id}`,
isProd: isProduction,
source: code,
scoped: block.scoped,
vars: !!block.vars,
modules: !!block.module,
postcssOptions: options.postcssOptions,
postcssPlugins: options.postcssPlugins,
Expand Down Expand Up @@ -300,6 +281,47 @@ export default function PluginVue(userOptions: Partial<Options> = {}): Plugin {
}
}

function getTemplateCompilerOptions(
options: Options,
descriptor: SFCDescriptor,
scopeId: string
): Omit<SFCTemplateCompileOptions, 'source'> | undefined {
const block = descriptor.template
if (!block) {
return
}

const isServer = options.target === 'node'
const isProduction =
process.env.NODE_ENV === 'production' || process.env.BUILD === 'production'
const hasScoped = descriptor.styles.some((s) => s.scoped)
const preprocessLang = block.lang
const preprocessOptions =
preprocessLang &&
options.templatePreprocessOptions &&
options.templatePreprocessOptions[preprocessLang]
return {
filename: descriptor.filename,
inMap: block.src ? undefined : block.map,
preprocessLang,
preprocessOptions,
preprocessCustomRequire: options.preprocessCustomRequire,
compiler: options.compiler,
ssr: isServer,
compilerOptions: {
...options.compilerOptions,
scopeId: hasScoped ? `data-v-${scopeId}` : undefined,
bindingMetadata: descriptor.scriptCompiled
? descriptor.scriptCompiled.bindings
: undefined,
ssrCssVars: isServer
? generateCssVars(descriptor, scopeId, isProduction)
: undefined,
},
transformAssetUrls: options.transformAssetUrls,
}
}

function createCustomBlockFilter(
queries?: string[]
): (type: string) => boolean {
Expand Down Expand Up @@ -336,15 +358,15 @@ type Query =
filename: string
vue: true
type: 'template'
id?: string
id: string
src?: true
}
| {
filename: string
vue: true
type: 'style'
index: number
id?: string
id: string
scoped?: boolean
module?: string | boolean
src?: true
Expand Down Expand Up @@ -418,25 +440,39 @@ function transformVueSFC(
const shortFilePath = relative(rootContext, resourcePath)
.replace(/^(\.\.[\/\\])+/, '')
.replace(/\\/g, '/')
const id = hash(isProduction ? shortFilePath + '\n' + code : shortFilePath)
const scopeId = hash(
isProduction ? shortFilePath + '\n' + code : shortFilePath
)
// feature information
const hasScoped = descriptor.styles.some((s) => s.scoped)

const templateImport = !descriptor.template
? ''
: getTemplateCode(descriptor, resourcePath, id, hasScoped, isServer)
const hasTemplateImport =
descriptor.template &&
// script setup compiles template inline, do not import again
(isServer || !descriptor.scriptSetup)

const templateImport = hasTemplateImport
? getTemplateCode(descriptor, resourcePath, scopeId, isServer)
: ''

const renderReplace = !descriptor.template
? ''
: isServer
? `script.ssrRender = ssrRender`
: `script.render = render`
const renderReplace = hasTemplateImport
? isServer
? `script.ssrRender = ssrRender`
: `script.render = render`
: ''

const scriptImport = getScriptCode(descriptor, resourcePath)
const scriptImport = getScriptCode(
descriptor,
resourcePath,
scopeId,
isProduction,
isServer,
getTemplateCompilerOptions(options, descriptor, scopeId)
)
const stylesCode = getStyleCode(
descriptor,
resourcePath,
id,
scopeId,
options.preprocessStyles
)
const customBlocksCode = getCustomBlock(
Expand All @@ -452,7 +488,7 @@ function transformVueSFC(
renderReplace,
]
if (hasScoped) {
output.push(`script.__scopeId = ${_(`data-v-${id}`)}`)
output.push(`script.__scopeId = ${_(`data-v-${scopeId}`)}`)
}
if (!isProduction) {
output.push(`script.__file = ${_(shortFilePath)}`)
Expand All @@ -467,7 +503,6 @@ function getTemplateCode(
descriptor: SFCDescriptor,
resourcePath: string,
id: string,
hasScoped: boolean,
isServer: boolean
) {
const renderFnName = isServer ? 'ssrRender' : 'render'
Expand All @@ -476,27 +511,39 @@ function getTemplateCode(
if (descriptor.template) {
const src = descriptor.template.src || resourcePath
const idQuery = `&id=${id}`
const scopedQuery = hasScoped ? `&scoped=true` : ``
const srcQuery = descriptor.template.src ? `&src` : ``
const attrsQuery = attrsToQuery(descriptor.template.attrs, 'js', true)
const query = `?vue&type=template${idQuery}${srcQuery}${scopedQuery}${attrsQuery}`
const query = `?vue&type=template${idQuery}${srcQuery}${attrsQuery}`
templateRequest = _(src + query)
templateImport = `import { ${renderFnName} } from ${templateRequest}`
}

return templateImport
}

function getScriptCode(descriptor: SFCDescriptor, resourcePath: string) {
function getScriptCode(
descriptor: SFCDescriptor,
resourcePath: string,
id: string,
isProd: boolean,
isServer: boolean,
templateOptions?: Partial<SFCTemplateCompileOptions>
) {
let scriptImport = `const script = {}`
if (descriptor.script || descriptor.scriptSetup) {
if (compileScript) {
descriptor.script = compileScript(descriptor)
descriptor.scriptCompiled = compileScript(descriptor, {
id,
isProd,
inlineTemplate: !isServer,
templateOptions,
})
}
if (descriptor.script) {
const src = descriptor.script.src || resourcePath
const attrsQuery = attrsToQuery(descriptor.script.attrs, 'js')
const srcQuery = descriptor.script.src ? `&src` : ``
const script = descriptor.scriptCompiled || descriptor.script
if (script) {
const src = script.src || resourcePath
const attrsQuery = attrsToQuery(script.attrs, 'js')
const srcQuery = script.src ? `&src` : ``
const query = `?vue&type=script${srcQuery}${attrsQuery}`
const scriptRequest = _(src + query)
scriptImport =
Expand Down Expand Up @@ -527,7 +574,7 @@ function getStyleCode(
)
// make sure to only pass id when necessary so that we don't inject
// duplicate tags when multiple components import the same css file
const idQuery = style.scoped ? `&id=${id}` : ``
const idQuery = `&id=${id}`
const srcQuery = style.src ? `&src` : ``
const query = `?vue&type=style&index=${i}${srcQuery}${idQuery}`
const styleRequest = src + query + attrsQuery
Expand Down
Loading

0 comments on commit d1a528f

Please sign in to comment.