Skip to content

Commit 11e3cb8

Browse files
committed
fix: generate treeshaking friendly code
1 parent 573fbd2 commit 11e3cb8

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/exportHelper.ts

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// runtime helper for setting properties on components
2+
// in a tree-shakable way
3+
export default (sfc: any, props: [string, string][]) => {
4+
for (const [key, val] of props) {
5+
sfc[key] = val
6+
}
7+
return sfc
8+
}

src/index.ts

+29-17
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ export interface VueLoaderOptions {
5151

5252
let errorEmitted = false
5353

54+
const exportHelperPath = JSON.stringify(require.resolve('./exportHelper'))
55+
5456
export default function loader(
5557
this: webpack.loader.LoaderContext,
5658
source: string
@@ -154,6 +156,10 @@ export default function loader(
154156
!!(descriptor.script || descriptor.scriptSetup || descriptor.template) &&
155157
options.hotReload !== false
156158

159+
// extra properties to attach to the script object
160+
// we need to do this in a tree-shaking friendly manner
161+
const propsToAttach: [string, string][] = []
162+
157163
// script
158164
let scriptImport = `const script = {}`
159165
let isTS = false
@@ -185,6 +191,7 @@ export default function loader(
185191
const query = `?vue&type=template${idQuery}${scopedQuery}${tsQuery}${attrsQuery}${resourceQuery}`
186192
templateRequest = stringifyRequest(src + query)
187193
templateImport = `import { ${renderFnName} } from ${templateRequest}`
194+
propsToAttach.push([renderFnName, renderFnName])
188195
}
189196

190197
// styles
@@ -210,7 +217,8 @@ export default function loader(
210217
)
211218
}
212219
if (!hasCSSModules) {
213-
stylesCode += `\nconst cssModules = script.__cssModules = {}`
220+
stylesCode += `\nconst cssModules = {}`
221+
propsToAttach.push([`__cssModules`, `cssModules`])
214222
hasCSSModules = true
215223
}
216224
stylesCode += genCSSModulesCode(
@@ -230,24 +238,20 @@ export default function loader(
230238
// TODO SSR critical CSS collection
231239
})
232240
if (asCustomElement) {
233-
stylesCode += `\nscript.styles = [${descriptor.styles.map(
234-
(_, i) => `_style_${i}`
235-
)}]`
241+
propsToAttach.push([
242+
`styles`,
243+
`[${descriptor.styles.map((_, i) => `_style_${i}`)}]`,
244+
])
236245
}
237246
}
238247

239-
let code = [
240-
templateImport,
241-
scriptImport,
242-
stylesCode,
243-
templateImport ? `script.${renderFnName} = ${renderFnName}` : ``,
244-
]
248+
let code = [templateImport, scriptImport, stylesCode]
245249
.filter(Boolean)
246250
.join('\n')
247251

248252
// attach scope Id for runtime use
249253
if (hasScoped) {
250-
code += `\nscript.__scopeId = "data-v-${id}"`
254+
propsToAttach.push([`__scopeId`, `"data-v-${id}"`])
251255
}
252256

253257
if (needsHotReload) {
@@ -258,13 +262,14 @@ export default function loader(
258262
if (!isProduction) {
259263
// Expose the file's full path in development, so that it can be opened
260264
// from the devtools.
261-
code += `\nscript.__file = ${JSON.stringify(
262-
rawShortFilePath.replace(/\\/g, '/')
263-
)}`
265+
propsToAttach.push([
266+
`__file`,
267+
JSON.stringify(rawShortFilePath.replace(/\\/g, '/')),
268+
])
264269
} else if (options.exposeFilename) {
265270
// Libraries can opt-in to expose their components' filenames in production builds.
266271
// For security reasons, only expose the file's basename in production.
267-
code += `\nscript.__file = ${JSON.stringify(path.basename(resourcePath))}`
272+
propsToAttach.push([`__file`, JSON.stringify(path.basename(resourcePath))])
268273
}
269274

270275
// custom blocks
@@ -282,14 +287,21 @@ export default function loader(
282287
const query = `?vue&type=custom&index=${i}${blockTypeQuery}${issuerQuery}${attrsQuery}${resourceQuery}`
283288
return (
284289
`import block${i} from ${stringifyRequest(src + query)}\n` +
285-
`if (typeof block${i} === 'function') block${i}(script)`
290+
`if (typeof block${i} === 'function') /*#__PURE__*/block${i}(script)`
286291
)
287292
})
288293
.join(`\n`) + `\n`
289294
}
290295

291296
// finalize
292-
code += `\n\nexport default script`
297+
if (!propsToAttach.length) {
298+
code += `\n\nexport default script`
299+
} else {
300+
code += `\n\nimport exportComponent from ${exportHelperPath}`
301+
code += `\nexport default /*#__PURE__*/exportComponent(script, [${propsToAttach
302+
.map(([key, val]) => `['${key}',${val}]`)
303+
.join(',')}])`
304+
}
293305
return code
294306
}
295307

0 commit comments

Comments
 (0)