From 4d1a818ad76bad6be50f1d92fcdf3a682a427268 Mon Sep 17 00:00:00 2001 From: Tom Nijmeijer Date: Mon, 5 Sep 2022 15:06:08 +0200 Subject: [PATCH 1/5] wip: Add imported components to runtimeOptions while compiling sfc's --- packages/compiler-sfc/src/compileScript.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 5a77e8a9463..f6adb53bd28 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -270,6 +270,7 @@ export function compileScript( // metadata that needs to be returned const bindingMetadata: BindingMetadata = {} const helperImports: Set = new Set() + const componentImports: Set = new Set() const userImports: Record = Object.create(null) const userImportAlias: Record = Object.create(null) const scriptBindings: Record = Object.create(null) @@ -364,6 +365,9 @@ export function compileScript( if (source === 'vue' && imported) { userImportAlias[imported] = local } + if (source.endsWith('.vue')) { + componentImports.add(local) + } // template usage check is only needed in non-inline mode, so we can skip // the work if inlineTemplate is true. @@ -1494,6 +1498,8 @@ export function compileScript( } else if (propsTypeDecl) { runtimeOptions += genRuntimeProps(typeDeclaredProps) } + const components = Array.from(componentImports).join(", ") + runtimeOptions += `\n components: { ${components} },` if (emitsRuntimeDecl) { runtimeOptions += `\n emits: ${scriptSetup.content .slice(emitsRuntimeDecl.start!, emitsRuntimeDecl.end!) From b1cbb55221a78a1645c20689fed51a43d591d025 Mon Sep 17 00:00:00 2001 From: Tom Nijmeijer Date: Mon, 5 Sep 2022 15:41:05 +0200 Subject: [PATCH 2/5] wip: Rewrite the applyStyles of the Vue custom element to be recursive --- packages/runtime-core/src/component.ts | 2 +- packages/runtime-core/src/hmr.ts | 4 +-- packages/runtime-dom/src/apiCustomElement.ts | 35 +++++++++++++------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index c70a6f87411..b57e4c0de1a 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -308,7 +308,7 @@ export interface ComponentInternalInstance { /** * custom element specific HMR method */ - ceReload?: (newStyles?: string[]) => void + ceReload?: (newComponent: ComponentOptions) => void // the rest are only for stateful components --------------------------------- diff --git a/packages/runtime-core/src/hmr.ts b/packages/runtime-core/src/hmr.ts index 3c3f5208bcc..130ed054e12 100644 --- a/packages/runtime-core/src/hmr.ts +++ b/packages/runtime-core/src/hmr.ts @@ -129,7 +129,7 @@ function reload(id: string, newComp: HMRComponent) { if (instance.ceReload) { // custom element hmrDirtyComponents.add(oldComp) - instance.ceReload((newComp as any).styles) + instance.ceReload(newComp) hmrDirtyComponents.delete(oldComp) } else if (instance.parent) { // 4. Force the parent instance to re-render. This will cause all updated @@ -142,7 +142,7 @@ function reload(id: string, newComp: HMRComponent) { (instance.parent.type as ComponentOptions).__asyncLoader && instance.parent.ceReload ) { - instance.parent.ceReload((newComp as any).styles) + instance.parent.ceReload(newComp) } } else if (instance.appContext.reload) { // root instance mounted via createApp() has a reload method diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index eabe83b6b9f..3359439937d 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -215,7 +215,7 @@ export class VueElement extends BaseClass { }).observe(this, { attributes: true }) const resolve = (def: InnerComponentDef) => { - const { props, styles } = def + const { props } = def const hasOptions = !isArray(props) const rawKeys = props ? (hasOptions ? Object.keys(props) : props) : [] @@ -252,7 +252,7 @@ export class VueElement extends BaseClass { } // apply CSS - this._applyStyles(styles) + this._applyStyles(def) // initial render this._update() @@ -320,13 +320,13 @@ export class VueElement extends BaseClass { instance.isCE = true // HMR if (__DEV__) { - instance.ceReload = newStyles => { + instance.ceReload = newComponent => { // always reset styles if (this._styles) { this._styles.forEach(s => this.shadowRoot!.removeChild(s)) this._styles.length = 0 } - this._applyStyles(newStyles) + this._applyStyles(newComponent) // if this is an async component, ceReload is called from the inner // component so no need to reload the async wrapper if (!(this._def as ComponentOptions).__asyncLoader) { @@ -362,17 +362,28 @@ export class VueElement extends BaseClass { return vnode } - private _applyStyles(styles: string[] | undefined) { - if (styles) { - styles.forEach(css => { - const s = document.createElement('style') - s.textContent = css - this.shadowRoot!.appendChild(s) + private _applyStyles(def: InnerComponentDef) { + const options = def as ComponentOptions; + + if (options.__asyncLoader) { + options.__asyncLoader().then(this._applyStyles.bind(this)); + return; + } + if (options.styles) { + for (const style of options.styles) { + const tag = document.createElement("style"); + tag.textContent = style; + this.shadowRoot!.appendChild(tag); // record for HMR if (__DEV__) { - ;(this._styles || (this._styles = [])).push(s) + (this._styles || (this._styles = [])).push(tag) } - }) + } + } + if (options.components) { + for (const sub of Object.values(options.components)) { + this._applyStyles(sub as ComponentOptions); + } } } } From 09692389b4165e62e867f62c2e038b2b0512b356 Mon Sep 17 00:00:00 2001 From: Tom Nijmeijer Date: Mon, 5 Sep 2022 15:53:48 +0200 Subject: [PATCH 3/5] wip: Only add components option when components are imported --- .../__tests__/__snapshots__/compileScript.spec.ts.snap | 2 ++ packages/compiler-sfc/src/compileScript.ts | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index b7fc9304b26..82fb1ff030c 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -965,6 +965,7 @@ import { ref } from 'vue' import * as tree from './tree' export default { + components: { Foo, bar }, setup(__props) { const count = ref(0) @@ -998,6 +999,7 @@ import ChildComp from './Child.vue' import vMyDir from './my-dir' export default { + components: { ChildComp, SomeOtherComp }, setup(__props) { diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index f6adb53bd28..ebf9cd39cfe 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -1498,8 +1498,10 @@ export function compileScript( } else if (propsTypeDecl) { runtimeOptions += genRuntimeProps(typeDeclaredProps) } - const components = Array.from(componentImports).join(", ") - runtimeOptions += `\n components: { ${components} },` + if (componentImports.size) { + const components = Array.from(componentImports).join(", ") + runtimeOptions += `\n components: { ${components} },` + } if (emitsRuntimeDecl) { runtimeOptions += `\n emits: ${scriptSetup.content .slice(emitsRuntimeDecl.start!, emitsRuntimeDecl.end!) From 60ea6ac9f4074c05d42e156418f16e6bb4829907 Mon Sep 17 00:00:00 2001 From: Tom Nijmeijer Date: Mon, 5 Sep 2022 16:30:20 +0200 Subject: [PATCH 4/5] wip: Add a test case for adding the components option --- .../__snapshots__/compileScript.spec.ts.snap | 16 ++++++++++++++++ .../compiler-sfc/__tests__/compileScript.spec.ts | 12 ++++++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index 82fb1ff030c..5f7563be4af 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -606,6 +606,22 @@ return { foo, bar, baz, y, z } }" `; +exports[`SFC compile + `) + assertCode(content) + // imported components should be declared in the components option + expect(content).toMatch('components: { SubComponent, OtherComponent }') + }); + test('