mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 17:35:57 +00:00
feat(components): build time sync loader (#383)
This commit is contained in:
parent
bb757045ec
commit
8e5e229031
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<hello-world />
|
<hello-world />
|
||||||
|
<nuxt3/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
5
examples/with-components/components/Nuxt3.vue
Normal file
5
examples/with-components/components/Nuxt3.vue
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<template>
|
||||||
|
<b style="color: #00C58E">
|
||||||
|
From Nuxt 3
|
||||||
|
</b>
|
||||||
|
</template>
|
@ -1,4 +1,5 @@
|
|||||||
import { defineNuxtConfig } from '@nuxt/kit'
|
import { defineNuxtConfig } from '@nuxt/kit'
|
||||||
|
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
|
vite: false
|
||||||
})
|
})
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"globby": "^11.0.4",
|
"globby": "^11.0.4",
|
||||||
"scule": "^0.2.1",
|
"scule": "^0.2.1",
|
||||||
"ufo": "^0.7.7",
|
"ufo": "^0.7.7",
|
||||||
|
"unplugin": "^0.0.5",
|
||||||
"upath": "^2.0.1"
|
"upath": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
47
packages/components/src/loader.ts
Normal file
47
packages/components/src/loader.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { createUnplugin } from 'unplugin'
|
||||||
|
import { parseQuery, parseURL } from 'ufo'
|
||||||
|
import { Component } from './types'
|
||||||
|
|
||||||
|
interface LoaderOptions {
|
||||||
|
getComponents(): Component[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const loaderPlugin = createUnplugin((options: LoaderOptions) => ({
|
||||||
|
name: 'nuxt-components-loader',
|
||||||
|
enforce: 'post',
|
||||||
|
transformInclude (id) {
|
||||||
|
const { pathname, search } = parseURL(id)
|
||||||
|
const query = parseQuery(search)
|
||||||
|
// we only transform render functions
|
||||||
|
// from `type=template` (in Webpack) and bare `.vue` file (in Vite)
|
||||||
|
return pathname.endsWith('.vue') && (query.type === 'template' || !search)
|
||||||
|
},
|
||||||
|
transform (code) {
|
||||||
|
return transform(code, options.getComponents())
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
function findComponent (components: Component[], name:string) {
|
||||||
|
return components.find(({ pascalName, kebabName }) => [pascalName, kebabName].includes(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform (content: string, components: Component[]) {
|
||||||
|
let num = 0
|
||||||
|
let imports = ''
|
||||||
|
const map = new Map<Component, string>()
|
||||||
|
|
||||||
|
// replace `_resolveComponent("...")` to direct import
|
||||||
|
const newContent = content.replace(/ _resolveComponent\("(.*?)"\)/g, (full, name) => {
|
||||||
|
const component = findComponent(components, name)
|
||||||
|
if (component) {
|
||||||
|
const identifier = map.get(component) || `__nuxt_component_${num++}`
|
||||||
|
map.set(component, identifier)
|
||||||
|
imports += `import ${identifier} from "${component.filePath}";`
|
||||||
|
return ` ${identifier}`
|
||||||
|
}
|
||||||
|
// no matched
|
||||||
|
return full
|
||||||
|
})
|
||||||
|
|
||||||
|
return `${imports}\n${newContent}`
|
||||||
|
}
|
@ -1,8 +1,9 @@
|
|||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import { defineNuxtModule, resolveAlias } from '@nuxt/kit'
|
import { defineNuxtModule, resolveAlias, addVitePlugin, addWebpackPlugin } from '@nuxt/kit'
|
||||||
import { resolve } from 'upath'
|
import { resolve } from 'upath'
|
||||||
import { scanComponents } from './scan'
|
import { scanComponents } from './scan'
|
||||||
import type { ComponentsDir } from './types'
|
import type { Component, ComponentsDir } from './types'
|
||||||
|
import { loaderPlugin } from './loader'
|
||||||
|
|
||||||
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
|
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
|
||||||
const isDirectory = (p: string) => { try { return fs.statSync(p).isDirectory() } catch (_e) { return false } }
|
const isDirectory = (p: string) => { try { return fs.statSync(p).isDirectory() } catch (_e) { return false } }
|
||||||
@ -14,6 +15,7 @@ export default defineNuxtModule({
|
|||||||
},
|
},
|
||||||
setup (options, nuxt) {
|
setup (options, nuxt) {
|
||||||
let componentDirs = []
|
let componentDirs = []
|
||||||
|
let components: Component[] = []
|
||||||
|
|
||||||
// Resolve dirs
|
// Resolve dirs
|
||||||
nuxt.hook('app:resolve', async () => {
|
nuxt.hook('app:resolve', async () => {
|
||||||
@ -56,7 +58,7 @@ export default defineNuxtModule({
|
|||||||
|
|
||||||
// Scan components and add to plugin
|
// Scan components and add to plugin
|
||||||
nuxt.hook('app:templates', async (app) => {
|
nuxt.hook('app:templates', async (app) => {
|
||||||
const components = await scanComponents(componentDirs, nuxt.options.srcDir!)
|
components = await scanComponents(componentDirs, nuxt.options.srcDir!)
|
||||||
await nuxt.callHook('components:extend', components)
|
await nuxt.callHook('components:extend', components)
|
||||||
if (!components.length) {
|
if (!components.length) {
|
||||||
return
|
return
|
||||||
@ -87,5 +89,11 @@ export default defineNuxtModule({
|
|||||||
await nuxt.callHook('builder:generateApp')
|
await nuxt.callHook('builder:generateApp')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (!nuxt.options.dev) {
|
||||||
|
const options = { getComponents: () => components }
|
||||||
|
addWebpackPlugin(loaderPlugin.webpack(options))
|
||||||
|
addVitePlugin(loaderPlugin.vite(options))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
21
yarn.lock
21
yarn.lock
@ -1413,6 +1413,7 @@ __metadata:
|
|||||||
scule: ^0.2.1
|
scule: ^0.2.1
|
||||||
ufo: ^0.7.7
|
ufo: ^0.7.7
|
||||||
unbuild: ^0.4.0
|
unbuild: ^0.4.0
|
||||||
|
unplugin: ^0.0.5
|
||||||
upath: ^2.0.1
|
upath: ^2.0.1
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: 3.1.5
|
vue: 3.1.5
|
||||||
@ -11955,6 +11956,26 @@ typescript@^4.3.5:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"unplugin@npm:^0.0.5":
|
||||||
|
version: 0.0.5
|
||||||
|
resolution: "unplugin@npm:0.0.5"
|
||||||
|
dependencies:
|
||||||
|
webpack-virtual-modules: ^0.4.3
|
||||||
|
peerDependencies:
|
||||||
|
rollup: ^2.50.0
|
||||||
|
vite: ^2.3.0
|
||||||
|
webpack: ^5.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
rollup:
|
||||||
|
optional: true
|
||||||
|
vite:
|
||||||
|
optional: true
|
||||||
|
webpack:
|
||||||
|
optional: true
|
||||||
|
checksum: 37f66f585365a9d7c26c03cc971329391839b13505942548be48ad834d7d5c68576e4defce92f9845bddd154c93340f8a1773337fce797f1cac1a1a34d6aac26
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"unstorage@npm:^0.2.3":
|
"unstorage@npm:^0.2.3":
|
||||||
version: 0.2.3
|
version: 0.2.3
|
||||||
resolution: "unstorage@npm:0.2.3"
|
resolution: "unstorage@npm:0.2.3"
|
||||||
|
Loading…
Reference in New Issue
Block a user