Skip to content

Commit 07b1ca2

Browse files
committed
fix(plugin-vue): generate tree-shakable code
1 parent 62065a8 commit 07b1ca2

File tree

3 files changed

+49
-21
lines changed

3 files changed

+49
-21
lines changed

packages/plugin-vue/src/helper.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const EXPORT_HELPER_ID = 'plugin-vue:export-helper'
2+
3+
export const helperCode = `
4+
export default (sfc, props) => {
5+
for (const [key, val] of props) {
6+
sfc[key] = val
7+
}
8+
return sfc
9+
}
10+
`

packages/plugin-vue/src/index.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { transformMain } from './main'
2525
import { handleHotUpdate } from './handleHotUpdate'
2626
import { transformTemplateAsModule } from './template'
2727
import { transformStyle } from './style'
28+
import { EXPORT_HELPER_ID, helperCode } from './helper'
2829

2930
// extend the descriptor so we can store the scopeId on it
3031
declare module '@vue/compiler-sfc' {
@@ -156,14 +157,22 @@ export default function vuePlugin(rawOptions: Options = {}): Plugin {
156157
options.devServer = server
157158
},
158159

159-
async resolveId(id, importer) {
160+
async resolveId(id) {
161+
// component export helper
162+
if (id === EXPORT_HELPER_ID) {
163+
return id
164+
}
160165
// serve sub-part requests (*?vue) as virtual modules
161166
if (parseVueRequest(id).query.vue) {
162167
return id
163168
}
164169
},
165170

166171
load(id, ssr = !!options.ssr) {
172+
if (id === EXPORT_HELPER_ID) {
173+
return helperCode
174+
}
175+
167176
const { filename, query } = parseVueRequest(id)
168177
// select corresponding block for sub-part virtual modules
169178
if (query.vue) {

packages/plugin-vue/src/main.ts

+29-20
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { isOnlyTemplateChanged, isEqualBlock } from './handleHotUpdate'
1515
import { RawSourceMap, SourceMapConsumer, SourceMapGenerator } from 'source-map'
1616
import { createRollupError } from './utils/error'
1717
import { transformWithEsbuild } from 'vite'
18+
import { EXPORT_HELPER_ID } from './helper'
1819

1920
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
2021
export async function transformMain(
@@ -39,6 +40,7 @@ export async function transformMain(
3940
}
4041

4142
// feature information
43+
const attachedProps: [string, string][] = []
4244
const hasScoped = descriptor.styles.some((s) => s.scoped)
4345

4446
// script
@@ -70,29 +72,27 @@ export async function transformMain(
7072
))
7173
}
7274

73-
let renderReplace = ''
7475
if (hasTemplateImport) {
75-
renderReplace = ssr
76-
? `_sfc_main.ssrRender = _sfc_ssrRender`
77-
: `_sfc_main.render = _sfc_render`
76+
attachedProps.push(
77+
ssr ? ['ssrRender', '_sfc_ssrRender'] : ['render', '_sfc_render']
78+
)
7879
} else {
7980
// #2128
8081
// User may empty the template but we didn't provide rerender function before
8182
if (
8283
prevDescriptor &&
8384
!isEqualBlock(descriptor.template, prevDescriptor.template)
8485
) {
85-
renderReplace = ssr
86-
? `_sfc_main.ssrRender = () => {}`
87-
: `_sfc_main.render = () => {}`
86+
attachedProps.push([ssr ? 'ssrRender' : 'render', '() => {}'])
8887
}
8988
}
9089

9190
// styles
9291
const stylesCode = await genStyleCode(
9392
descriptor,
9493
pluginContext,
95-
asCustomElement
94+
asCustomElement,
95+
attachedProps
9696
)
9797

9898
// custom blocks
@@ -102,17 +102,14 @@ export async function transformMain(
102102
scriptCode,
103103
templateCode,
104104
stylesCode,
105-
customBlocksCode,
106-
renderReplace
105+
customBlocksCode
107106
]
108107
if (hasScoped) {
109-
output.push(
110-
`_sfc_main.__scopeId = ${JSON.stringify(`data-v-${descriptor.id}`)}`
111-
)
108+
attachedProps.push([`__scopeId`, JSON.stringify(`data-v-${descriptor.id}`)])
112109
}
113110
if (devServer && !isProduction) {
114111
// expose filename during serve for devtools to pickup
115-
output.push(`_sfc_main.__file = ${JSON.stringify(filename)}`)
112+
attachedProps.push([`__file`, JSON.stringify(filename)])
116113
}
117114

118115
// HMR
@@ -185,7 +182,16 @@ export async function transformMain(
185182
resolvedMap.sourcesContent = templateMap.sourcesContent
186183
}
187184

188-
output.push(`export default _sfc_main`)
185+
if (!attachedProps.length) {
186+
output.push(`export default _sfc_main`)
187+
} else {
188+
output.push(
189+
`import _export_sfc from '${EXPORT_HELPER_ID}'`,
190+
`export default /*#__PURE__*/_export_sfc(_sfc_main, [${attachedProps
191+
.map(([key, val]) => `['${key}',${val}]`)
192+
.join(',')}])`
193+
)
194+
}
189195

190196
// handle TS transpilation
191197
let resolvedCode = output.join('\n')
@@ -290,7 +296,8 @@ async function genScriptCode(
290296
async function genStyleCode(
291297
descriptor: SFCDescriptor,
292298
pluginContext: PluginContext,
293-
asCustomElement: boolean
299+
asCustomElement: boolean,
300+
attachedProps: [string, string][]
294301
) {
295302
let stylesCode = ``
296303
let hasCSSModules = false
@@ -315,7 +322,8 @@ async function genStyleCode(
315322
)
316323
}
317324
if (!hasCSSModules) {
318-
stylesCode += `\nconst cssModules = _sfc_main.__cssModules = {}`
325+
stylesCode += `\nconst cssModules = {}`
326+
attachedProps.push([`__cssModules`, `cssModules`])
319327
hasCSSModules = true
320328
}
321329
stylesCode += genCSSModulesCode(i, styleRequest, style.module)
@@ -331,9 +339,10 @@ async function genStyleCode(
331339
// TODO SSR critical CSS collection
332340
}
333341
if (asCustomElement) {
334-
stylesCode += `\n_sfc_main.styles = [${descriptor.styles
335-
.map((_, i) => `_style_${i}`)
336-
.join(',')}]`
342+
attachedProps.push([
343+
`styles`,
344+
`[${descriptor.styles.map((_, i) => `_style_${i}`).join(',')}]`
345+
])
337346
}
338347
}
339348
return stylesCode

0 commit comments

Comments
 (0)