2021-08-09 21:54:44 +00:00
|
|
|
import { statSync } from 'fs'
|
2022-02-07 20:48:25 +00:00
|
|
|
import { resolve, basename } from 'pathe'
|
2022-02-28 10:07:20 +00:00
|
|
|
import { defineNuxtModule, resolveAlias, addVitePlugin, addWebpackPlugin, addTemplate, addPluginTemplate } from '@nuxt/kit'
|
2021-11-21 16:14:46 +00:00
|
|
|
import type { Component, ComponentsDir, ComponentsOptions } from '@nuxt/schema'
|
2021-09-23 17:57:37 +00:00
|
|
|
import { componentsTemplate, componentsTypeTemplate } from './templates'
|
2021-06-18 16:50:03 +00:00
|
|
|
import { scanComponents } from './scan'
|
2021-07-28 12:11:32 +00:00
|
|
|
import { loaderPlugin } from './loader'
|
2021-06-18 16:50:03 +00:00
|
|
|
|
|
|
|
const isPureObjectOrString = (val: any) => (!Array.isArray(val) && typeof val === 'object') || typeof val === 'string'
|
2021-08-09 21:54:44 +00:00
|
|
|
const isDirectory = (p: string) => { try { return statSync(p).isDirectory() } catch (_e) { return false } }
|
2022-02-07 20:48:25 +00:00
|
|
|
function compareDirByPathLength ({ path: pathA }, { path: pathB }) {
|
|
|
|
return pathB.split(/[\\/]/).filter(Boolean).length - pathA.split(/[\\/]/).filter(Boolean).length
|
|
|
|
}
|
2021-06-18 16:50:03 +00:00
|
|
|
|
2021-11-19 12:22:27 +00:00
|
|
|
export default defineNuxtModule<ComponentsOptions>({
|
2022-01-05 18:09:53 +00:00
|
|
|
meta: {
|
|
|
|
name: 'components',
|
|
|
|
configKey: 'components'
|
|
|
|
},
|
2021-06-18 16:50:03 +00:00
|
|
|
defaults: {
|
2022-02-24 16:20:49 +00:00
|
|
|
dirs: []
|
2021-06-18 16:50:03 +00:00
|
|
|
},
|
2022-02-07 20:48:25 +00:00
|
|
|
setup (componentOptions, nuxt) {
|
2021-06-18 16:50:03 +00:00
|
|
|
let componentDirs = []
|
2022-02-25 10:16:24 +00:00
|
|
|
const components: Component[] = []
|
2021-06-18 16:50:03 +00:00
|
|
|
|
2022-02-07 20:48:25 +00:00
|
|
|
const normalizeDirs = (dir: any, cwd: string) => {
|
|
|
|
if (Array.isArray(dir)) {
|
|
|
|
return dir.map(dir => normalizeDirs(dir, cwd)).flat().sort(compareDirByPathLength)
|
|
|
|
}
|
|
|
|
if (dir === true || dir === undefined) {
|
|
|
|
return [{ path: resolve(cwd, 'components') }]
|
|
|
|
}
|
|
|
|
if (typeof dir === 'string') {
|
|
|
|
return {
|
|
|
|
path: resolve(cwd, resolveAlias(dir, {
|
|
|
|
...nuxt.options.alias,
|
|
|
|
'~': cwd
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
2022-03-16 20:36:30 +00:00
|
|
|
if (!dir) {
|
|
|
|
return []
|
2022-02-24 16:20:49 +00:00
|
|
|
}
|
2022-03-16 20:36:30 +00:00
|
|
|
const dirs = (dir.dirs || [dir]).filter(_dir => _dir.path)
|
|
|
|
return dirs.map(_dir => ({
|
|
|
|
..._dir,
|
|
|
|
path: resolve(cwd, resolveAlias(_dir.path, {
|
|
|
|
...nuxt.options.alias,
|
|
|
|
'~': cwd
|
|
|
|
}))
|
|
|
|
}))
|
2022-02-07 20:48:25 +00:00
|
|
|
}
|
|
|
|
|
2021-06-18 16:50:03 +00:00
|
|
|
// Resolve dirs
|
|
|
|
nuxt.hook('app:resolve', async () => {
|
2022-03-16 20:36:30 +00:00
|
|
|
// components/ dirs from all layers
|
|
|
|
const allDirs = nuxt.options._layers
|
|
|
|
.map(layer => normalizeDirs(layer.config.components, layer.cwd))
|
|
|
|
.flat()
|
2022-02-07 20:48:25 +00:00
|
|
|
|
|
|
|
await nuxt.callHook('components:dirs', allDirs)
|
2021-06-18 16:50:03 +00:00
|
|
|
|
2022-02-07 20:48:25 +00:00
|
|
|
componentDirs = allDirs.filter(isPureObjectOrString).map((dir) => {
|
2021-06-18 16:50:03 +00:00
|
|
|
const dirOptions: ComponentsDir = typeof dir === 'object' ? dir : { path: dir }
|
2022-02-07 21:00:20 +00:00
|
|
|
const dirPath = resolveAlias(dirOptions.path)
|
2021-06-18 16:50:03 +00:00
|
|
|
const transpile = typeof dirOptions.transpile === 'boolean' ? dirOptions.transpile : 'auto'
|
2021-11-02 15:27:42 +00:00
|
|
|
const extensions = (dirOptions.extensions || nuxt.options.extensions).map(e => e.replace(/^\./g, ''))
|
2021-06-18 16:50:03 +00:00
|
|
|
|
|
|
|
dirOptions.level = Number(dirOptions.level || 0)
|
|
|
|
|
2021-06-21 11:50:28 +00:00
|
|
|
const present = isDirectory(dirPath)
|
2022-02-07 20:48:25 +00:00
|
|
|
if (!present && basename(dirOptions.path) !== 'components') {
|
2021-06-18 16:50:03 +00:00
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
console.warn('Components directory not found: `' + dirPath + '`')
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
2022-02-18 09:37:11 +00:00
|
|
|
global: componentOptions.global,
|
2021-06-18 16:50:03 +00:00
|
|
|
...dirOptions,
|
2021-06-21 11:50:28 +00:00
|
|
|
// TODO: https://github.com/nuxt/framework/pull/251
|
|
|
|
enabled: true,
|
2021-06-18 16:50:03 +00:00
|
|
|
path: dirPath,
|
|
|
|
extensions,
|
|
|
|
pattern: dirOptions.pattern || `**/*.{${extensions.join(',')},}`,
|
|
|
|
ignore: [
|
|
|
|
'**/*{M,.m,-m}ixin.{js,ts,jsx,tsx}', // ignore mixins
|
|
|
|
'**/*.d.ts', // .d.ts files
|
|
|
|
...(dirOptions.ignore || [])
|
|
|
|
],
|
|
|
|
transpile: (transpile === 'auto' ? dirPath.includes('node_modules') : transpile)
|
|
|
|
}
|
|
|
|
}).filter(d => d.enabled)
|
|
|
|
|
|
|
|
nuxt.options.build!.transpile!.push(...componentDirs.filter(dir => dir.transpile).map(dir => dir.path))
|
|
|
|
})
|
|
|
|
|
2022-02-25 10:16:24 +00:00
|
|
|
const options = { components, buildDir: nuxt.options.buildDir }
|
2022-01-27 12:46:28 +00:00
|
|
|
|
2022-02-25 10:16:24 +00:00
|
|
|
addTemplate({
|
|
|
|
...componentsTypeTemplate,
|
|
|
|
options
|
|
|
|
})
|
2022-01-27 12:46:28 +00:00
|
|
|
|
2022-02-28 10:07:20 +00:00
|
|
|
addPluginTemplate({
|
2022-02-25 10:16:24 +00:00
|
|
|
...componentsTemplate,
|
|
|
|
options
|
|
|
|
})
|
2021-06-18 16:50:03 +00:00
|
|
|
|
2022-02-25 10:16:24 +00:00
|
|
|
// Scan components and add to plugin
|
|
|
|
nuxt.hook('app:templates', async () => {
|
|
|
|
options.components = await scanComponents(componentDirs, nuxt.options.srcDir!)
|
2022-02-28 10:07:20 +00:00
|
|
|
await nuxt.callHook('components:extend', options.components)
|
2021-06-18 16:50:03 +00:00
|
|
|
})
|
|
|
|
|
2021-08-09 21:54:44 +00:00
|
|
|
nuxt.hook('prepare:types', ({ references }) => {
|
2022-02-07 10:20:01 +00:00
|
|
|
references.push({ path: resolve(nuxt.options.buildDir, 'types/components.d.ts') })
|
2021-08-09 21:54:44 +00:00
|
|
|
})
|
|
|
|
|
2021-06-18 16:50:03 +00:00
|
|
|
// Watch for changes
|
|
|
|
nuxt.hook('builder:watch', async (event, path) => {
|
|
|
|
if (!['add', 'unlink'].includes(event)) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
const fPath = resolve(nuxt.options.rootDir, path)
|
|
|
|
if (componentDirs.find(dir => fPath.startsWith(dir.path))) {
|
|
|
|
await nuxt.callHook('builder:generateApp')
|
|
|
|
}
|
|
|
|
})
|
2021-07-28 12:11:32 +00:00
|
|
|
|
2022-02-28 10:07:20 +00:00
|
|
|
const loaderOptions = { getComponents: () => options.components }
|
2021-10-29 11:36:55 +00:00
|
|
|
addWebpackPlugin(loaderPlugin.webpack(loaderOptions))
|
|
|
|
addVitePlugin(loaderPlugin.vite(loaderOptions))
|
2021-06-18 16:50:03 +00:00
|
|
|
}
|
|
|
|
})
|