Skip to content
This repository was archived by the owner on Apr 6, 2023. It is now read-only.

Commit d093fa9

Browse files
committed
feat: it works!
1 parent aebd09d commit d093fa9

File tree

7 files changed

+58
-45
lines changed

7 files changed

+58
-45
lines changed

examples/with-components/components/ClientAndServer.server.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,7 @@
44
<slot />
55
</div>
66
</template>
7+
8+
<script setup>
9+
console.log('Hi from Server Component!')
10+
</script>

examples/with-components/nuxt.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { defineNuxtConfig } from 'nuxt3'
22

33
export default defineNuxtConfig({
4-
vite: true,
4+
vite: false,
55
components: {
66
dirs: [
77
'~/components',

packages/nuxt3/src/app/components/client-only.mjs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { ref, onMounted, defineComponent, createElementBlock } from 'vue'
1+
import { ref, onMounted, defineComponent, createElementBlock, h } from 'vue'
22

3-
export default defineComponent({
3+
const ClientOnly = defineComponent({
44
name: 'ClientOnly',
55
// eslint-disable-next-line vue/require-prop-types
66
props: ['fallback', 'placeholder', 'placeholderTag', 'fallbackTag'],
@@ -17,3 +17,21 @@ export default defineComponent({
1717
}
1818
}
1919
})
20+
21+
export function wrapClientOnly (component, mode) {
22+
return defineComponent({
23+
name: 'ClientOnlyWarpper',
24+
setup (props, { attrs, slots }) {
25+
const mounted = ref(false)
26+
onMounted(() => { mounted.value = true })
27+
return () => {
28+
if (mounted.value === (mode !== 'server')) {
29+
return h(component, { props, attrs }, slots)
30+
}
31+
return h('div')
32+
}
33+
}
34+
})
35+
}
36+
37+
export default ClientOnly
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineComponent, createElementBlock } from 'vue'
2+
3+
export default defineComponent({
4+
name: 'Empty',
5+
render () {
6+
return createElementBlock('div')
7+
}
8+
})

packages/nuxt3/src/components/loader.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ function transform (content: string, components: Component[], mode: 'server' | '
3131
let num = 0
3232
let imports = ''
3333
const map = new Map<Component, string>()
34+
let hasEnvComponents = false
3435

3536
// replace `_resolveComponent("...")` to direct import
3637
const newContent = content.replace(/ _resolveComponent\("(.*?)"\)/g, (full, name) => {
@@ -39,11 +40,19 @@ function transform (content: string, components: Component[], mode: 'server' | '
3940
const identifier = map.get(component) || `__nuxt_component_${num++}`
4041
map.set(component, identifier)
4142
imports += `import ${identifier} from "${getComponentPath(component, mode)}";`
43+
if (component.envPaths) {
44+
hasEnvComponents = true
45+
return ` wrapClientOnly(${identifier}, '${mode}')`
46+
}
4247
return ` ${identifier}`
4348
}
4449
// no matched
4550
return full
4651
})
4752

53+
if (hasEnvComponents) {
54+
imports = 'import { wrapClientOnly } from \'#app/components/client-only\';' + imports
55+
}
56+
4857
return `${imports}\n${newContent}`
4958
}

packages/nuxt3/src/components/module.ts

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -66,24 +66,6 @@ export default defineNuxtModule<ComponentsOptions>({
6666
return
6767
}
6868

69-
// // Handle environment-specify components
70-
// components.filter(i => i.envPaths).forEach((component) => {
71-
// const filename = `env-${component.pascalName}.vue`
72-
// component.filePath = `#build/${filename}`
73-
// component.shortPath = `#build/${filename}`
74-
// app.templates.push({
75-
// filename,
76-
// write: true,
77-
// getContents: () => getEnvComponentTemplate(component)
78-
// })
79-
// })
80-
81-
app.templates.push({
82-
filename: 'Empty.vue',
83-
write: true,
84-
getContents: () => '<template></template>'
85-
})
86-
8769
app.templates.push({
8870
...componentsClientTemplate,
8971
options: { components }
@@ -130,14 +112,14 @@ export default defineNuxtModule<ComponentsOptions>({
130112
}))
131113
})
132114

133-
// TODO: webpack
134115
nuxt.hook('webpack:config', (configs) => {
135116
configs.forEach((config) => {
136-
console.log(config)
117+
config.plugins = config.plugins || []
118+
config.plugins.push(loaderPlugin.webpack({
119+
getComponents,
120+
mode: config.name === 'client' ? 'client' : 'server'
121+
}))
137122
})
138123
})
139-
140-
// addWebpackPlugin(loaderPlugin.webpack(loaderOptions))
141-
// addVitePlugin(loaderPlugin.vite(loaderOptions))
142124
}
143125
})

packages/nuxt3/src/components/templates.ts

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -22,38 +22,30 @@ const createImportMagicComments = (options: ImportMagicCommentsOptions) => {
2222
].filter(Boolean).join(', ')
2323
}
2424

25-
// export const getEnvComponentTemplate = (component: Component) => `
26-
// <script setup>
27-
// import Client from '${component.envPaths.client}'
28-
// ${component.envPaths.server ? `import Server from '${component.envPaths.server}'` : ''}
29-
// </script>
30-
31-
// <template>
32-
// <ClientOnly>
33-
// <Client v-bind="$attrs"><slot/></Client>
34-
// ${component.envPaths.server ? '<template #fallback><Server v-bind="$attrs"><slot/></Server></template>' : ''}
35-
// </ClientOnly>
36-
// </template>
37-
// `
38-
3925
export function getComponentPath (component: Component, mode?: NuxtPlugin['mode']) {
4026
if (!component.envPaths || !mode || mode === 'all') {
4127
return component.filePath
4228
}
43-
return mode === 'client'
29+
const envPath = mode === 'client'
4430
? component.envPaths.client
45-
: component.envPaths.server || '#build/Empty.vue'
31+
: component.envPaths.server
32+
return envPath || '#app/components/nuxt-empty'
4633
}
4734

4835
function getComponentTemplate (components: Component[], mode: NuxtPlugin['mode']) {
49-
return `import { defineAsyncComponent } from 'vue'
36+
return `import { defineAsyncComponent, h as __h } from 'vue'
37+
import { wrapClientOnly } from '#app/components/client-only'
5038
5139
const components = {
5240
${components.filter(c => c.global !== false).map((c) => {
53-
const exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']`
41+
let exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']`
5442
const magicComments = createImportMagicComments(c)
43+
const path = getComponentPath(c, mode)
44+
if (c.envPaths) {
45+
exp = `wrapClientOnly(${exp}, '${mode}')`
46+
}
5547
56-
return ` '${c.pascalName}': defineAsyncComponent(() => import('${getComponentPath(c, mode)}' /* ${magicComments} */).then(c => ${exp}))`
48+
return ` '${c.pascalName}': defineAsyncComponent(() => import('${path}' /* ${magicComments} */).then(c => ${exp}))`
5749
}).join(',\n')}
5850
}
5951

0 commit comments

Comments
 (0)