From a0ae6e53a57bdea523e7df69ef88a561488eccd4 Mon Sep 17 00:00:00 2001 From: Mehmet Date: Mon, 25 Dec 2023 08:22:04 +0300 Subject: [PATCH] feat(nuxt): interdependencies and sequencing of modules (#79) * feat: interdependencies and sequencing of modules * fix: lint * Refactor setupPergel function and update ResolvedPergelOptions interface * Refactor definePergelModule function to use defu for options merging * Add new seedPaths option to DrizzleConfig * Refactor GraphQLYoga module configuration * Update setupModules.ts to include additional parameters * Update module configurations * Refactor module options and setup in Nuxt runtime * Enable drizzle in nuxt.config.ts and add drizzle-related scripts and configurations in README.yaml * Add debug option to pergel configuration --- packages/nuxt/playground/nuxt.config.ts | 1 + .../nuxt/src/runtime/core/definePergel.ts | 96 +++--- .../nuxt/src/runtime/core/setupModules.ts | 295 ++++++++++++++---- packages/nuxt/src/runtime/core/setupPergel.ts | 69 ++-- .../nuxt/src/runtime/core/types/module.ts | 140 ++++++--- .../src/runtime/core/utils/addModuleDTS.ts | 12 +- .../src/runtime/core/utils/generateYaml.ts | 21 +- packages/nuxt/src/runtime/core/utils/index.ts | 2 +- .../runtime/core/utils/moduleRuntimeConfig.ts | 9 +- .../runtime/core/utils/useModuleOptions.ts | 15 + packages/nuxt/src/runtime/modules/S3/index.ts | 9 +- .../nuxt/src/runtime/modules/bullmq/export.ts | 0 .../nuxt/src/runtime/modules/bullmq/index.ts | 15 +- .../nuxt/src/runtime/modules/drizzle/core.ts | 3 +- .../modules/drizzle/drivers/postgres/index.ts | 94 +++--- .../nuxt/src/runtime/modules/drizzle/index.ts | 56 ++-- .../nuxt/src/runtime/modules/drizzle/types.ts | 5 + .../src/runtime/modules/graphqlYoga/index.ts | 40 ++- .../graphqlYoga/utils/generateCodegen.ts | 3 +- .../utils/generateGraphqlTemplate.ts | 24 +- .../src/runtime/modules/json2csv/index.ts | 7 +- .../src/runtime/modules/nodeCron/index.ts | 7 +- .../nuxt/src/runtime/modules/ses/index.ts | 10 +- 23 files changed, 561 insertions(+), 372 deletions(-) create mode 100644 packages/nuxt/src/runtime/core/utils/useModuleOptions.ts delete mode 100644 packages/nuxt/src/runtime/modules/bullmq/export.ts diff --git a/packages/nuxt/playground/nuxt.config.ts b/packages/nuxt/playground/nuxt.config.ts index 6efbae42..49f07f21 100644 --- a/packages/nuxt/playground/nuxt.config.ts +++ b/packages/nuxt/playground/nuxt.config.ts @@ -47,6 +47,7 @@ export default defineNuxtConfig({ }), ], pergel: { + debug: true, projects: { test: { S3: true, diff --git a/packages/nuxt/src/runtime/core/definePergel.ts b/packages/nuxt/src/runtime/core/definePergel.ts index 60c9286a..f3abb2c6 100644 --- a/packages/nuxt/src/runtime/core/definePergel.ts +++ b/packages/nuxt/src/runtime/core/definePergel.ts @@ -1,89 +1,62 @@ import defu from 'defu' +import { useNuxt } from '@nuxt/kit' import type { ModuleDefinition, ModuleOptions, ModuleSetupReturn, NuxtPergel, PergelModule, + ResolvedModuleOptions, } from './types' -import { generateProjectReadme } from './utils/generateYaml' -export function definePergelModule( - definition: ModuleDefinition | PergelModule, -): PergelModule { +export function definePergelModule( + definition: ModuleDefinition | PergelModule, +): PergelModule { if (typeof definition === 'function') return definePergelModule({ setup: definition }) // Normalize definition and meta - const module: ModuleDefinition & Required, 'meta'>> = defu(definition, { meta: {} }) + const module: ModuleDefinition & Required, 'meta'>> = defu(definition, { meta: {} }) if (module.meta.configKey === undefined) module.meta.configKey = module.meta.name - async function preparationModule(data: { nuxt: NuxtPergel }) { - const { nuxt } = data - const dependencies = module.meta.dependencies instanceof Function ? module.meta.dependencies(data.nuxt._pergel._module.options) : module.meta.dependencies ?? {} - const devDependencies = module.meta.devDependencies instanceof Function ? module.meta.devDependencies(data.nuxt._pergel._module.options) : module.meta.devDependencies ?? {} + async function getOptions(inlineOptions: RootOptions, moduleOptions: ResolvedModuleOptions, nuxt: NuxtPergel = useNuxt()) { + const defaultModule = module.defaults instanceof Function ? module.defaults({ nuxt, rootOptions: inlineOptions, moduleOptions }) : module.defaults - if (Object.keys(dependencies).length > 0 || Object.keys(devDependencies).length > 0) { - generateProjectReadme(nuxt, ({ addCommentBlock }) => ({ - ...addCommentBlock('If pergel cli is installed, you can run `pergel install` automatically to install'), - packageJson: { - dependencies: `"${Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).join(', ')}"`, - devDependencies: `"${Object.entries(devDependencies).map(([name, version]) => `${name}@${version}`).join(', ')}"`, - }, - })) - } - - if (module.meta.name) { - nuxt._pergel.activeModules[nuxt._pergel._module.projectName] ??= {} - nuxt._pergel.activeModules[nuxt._pergel._module.projectName][module.meta.name] ??= {} - } - - const defaultModule = module.defaults instanceof Function ? module.defaults({ nuxt }) : module.defaults + const rootOptions = (nuxt._pergel.rootOptions.projects[moduleOptions.projectName] as any)[moduleOptions.moduleName] ?? {} + const _options = defu(rootOptions, defaultModule) - const userModuleOptions = (nuxt._pergel.rootOptions.projects[nuxt._pergel._module.projectName] as any)[nuxt._pergel._module.moduleName] ?? {} + return Promise.resolve(_options) + } - const moduleOptions = defu({ - ...nuxt._pergel._module, - options: { - ...userModuleOptions, - }, - } satisfies NuxtPergel['_pergel']['_module'], { - // User send S3 module options - options: { - ...defaultModule, - }, - } as NuxtPergel['_pergel']['_module']) as NuxtPergel['_pergel']['_module'] + async function normalizedModule(this: any, data: { nuxt: NuxtPergel, rootOptions: RootOptions, moduleOptions: ResolvedModuleOptions }) { + const options = await getOptions(data.rootOptions, data.moduleOptions, data.nuxt) - // TODO: Fix any type - // @ts-ignore - nuxt._pergel.projects[nuxt._pergel._module.projectName][nuxt._pergel._module.moduleName].options = moduleOptions.options as any + const key = `pergel:${module.meta.configKey}` + const mark = performance.mark(key) + if (!this.prepare) { + // Resolve module and options - // TODO: Fix any type - nuxt._pergel._module = moduleOptions as any - nuxt._pergel.activeModules[nuxt._pergel._module.projectName][nuxt._pergel._module.moduleName] = defu( - nuxt._pergel.activeModules[nuxt._pergel._module.projectName][nuxt._pergel._module.moduleName], - moduleOptions.options, - ) as any + const res = await module.setup?.call(null as any, { nuxt: data.nuxt, options, rootOptions: data.rootOptions, moduleOptions: data.moduleOptions }) ?? {} + const perf = performance.measure(key, mark) + const setupTime = perf ? Math.round(perf.duration * 100) / 100 : 0 - return Promise.resolve(moduleOptions) - } + // Check if module is ignored + if (res === false) + return false - async function normalizedModule(this: any, data: { nuxt: NuxtPergel }) { - // Resolve module and options - await preparationModule({ nuxt: data.nuxt }) + // Return module install result + return defu(res, { + timings: { + setup: setupTime, + }, + }) + } - const key = `pergel:${module.meta.configKey}` - const mark = performance.mark(key) - const res = await module.setup?.call(null as any, { nuxt: data.nuxt }) ?? {} + const res = {} const perf = performance.measure(key, mark) const setupTime = perf ? Math.round(perf.duration * 100) / 100 : 0 - - // Check if module is ignored - if (res === false) - return false - // Return module install result return defu(res, { timings: { @@ -92,5 +65,8 @@ export function definePergelModule( }) } - return normalizedModule as PergelModule + normalizedModule.getMeta = () => Promise.resolve(module.meta) as any + normalizedModule.getOptions = getOptions as any + + return normalizedModule } diff --git a/packages/nuxt/src/runtime/core/setupModules.ts b/packages/nuxt/src/runtime/core/setupModules.ts index e8c3a7ea..039b94c2 100644 --- a/packages/nuxt/src/runtime/core/setupModules.ts +++ b/packages/nuxt/src/runtime/core/setupModules.ts @@ -1,97 +1,256 @@ -import { join } from 'node:path' +import { join, resolve } from 'node:path' import { readdirSync } from 'node:fs' import type { Nuxt } from '@nuxt/schema' import type { Resolver } from '@nuxt/kit' import consola from 'consola' import type { ModuleName, PergelModule } from './types' import { generatePergelTemplate } from './utils/generatePergelTemplate' +import { generateProjectReadme } from './utils/generateYaml' + +type PrepareModules = { + [project: string]: { + [module: string]: { + defineModule: PergelModule + waitModule?: string[] + } + } +} + +class CircularDependencyError extends Error { + constructor(message: string) { + super(message) + this.name = 'CircularDependencyError' + } +} + +async function initModules(nuxt: Nuxt, resolver: Resolver) { + const projects = nuxt._pergel.rootOptions.projects + + const prepareModules: PrepareModules = {} + + try { + for await (const [projectName, modules] of Object.entries(projects)) { + for await (const [moduleName, moduleValue] of Object.entries(modules)) { + if (typeof moduleValue === 'boolean' && moduleValue === false) + continue + + if ( + (typeof moduleValue === 'object' && moduleValue === null) + || (typeof moduleValue === 'object' && !moduleValue) + ) + continue + + if (typeof moduleValue === 'string' && moduleValue === '') + continue + + nuxt._pergel.projects[projectName] ??= {} as any + (nuxt._pergel.projects[projectName] as any)[moduleName] = { + projectDir: join(nuxt._pergel.pergelDir, projectName), + moduleDir: join(nuxt._pergel.pergelDir, projectName, moduleName), + dir: { + project: join(nuxt._pergel.dir.pergel, projectName), + module: join(nuxt._pergel.dir.pergel, projectName, moduleName), + root: join(nuxt._pergel.dir.pergel), + }, + } + + let pergelModule: PergelModule + + const module = (nuxt._pergel.projects[projectName as any] as any)[moduleName as any] + + try { + const getIndexExt = () => { + const datas = readdirSync(resolver.resolve(join('runtime', 'modules', moduleName))) + const indexExt = datas.find(file => file.includes('index') && !file.includes('.d.')) + if (!indexExt) + throw new Error(`Module ${moduleName} does not have index file`) + + return indexExt + } + const indexPath = getIndexExt() + + pergelModule = await import( + resolver.resolve(join('runtime', 'modules', moduleName, indexPath)) + ).then(m => m.default).catch((res) => { + consola.error(`Module ${moduleName} failed to import`) + consola.error(res) + }) + } + + catch (error) { + consola.error(`Module ${moduleName} failed to import`) + throw error + } + // Throw error if input is not a function + if (typeof pergelModule !== 'function') + throw new TypeError(`Nuxt module should be a function: ${pergelModule}`) + + // const resolvedModule = await pergelModule({ nuxt: nuxt }) + const resolvedModule = await pergelModule.call({ + prepare: true, + } as any, { + nuxt, + options: {}, + rootOptions: module, + moduleOptions: { + dir: { + module: join(nuxt._pergel.dir.pergel, projectName, moduleName), + project: join(nuxt._pergel.dir.pergel, projectName), + root: join(nuxt._pergel.dir.pergel), + }, + moduleName: moduleName as ModuleName, + projectName, + moduleDir: resolve(nuxt._pergel.pergelDir, projectName, moduleName), + }, + }) + + if (resolvedModule === false /* setup aborted */ || resolvedModule === undefined /* setup failed */ || typeof resolvedModule === 'string' /* setup failed */) { + consola.error(`Module ${moduleName} failed to setup`) + continue + } + + prepareModules[projectName] ??= {} + prepareModules[projectName as any][moduleName as any] ??= {} as any + prepareModules[projectName][moduleName].defineModule = pergelModule + prepareModules[projectName][moduleName].waitModule = await waitModule({ + defineModule: pergelModule, + nuxt, + moduleName, + projectName, + }) + } + } + } + catch (error) { + consola.error(error) + } + + return prepareModules +} + +async function waitModule( + data: { + defineModule: PergelModule + nuxt: Nuxt + moduleName: string + projectName: string + }, +) { + const { defineModule, nuxt, moduleName, projectName } = data + const rootOptions = (nuxt._pergel.rootOptions.projects[projectName] as any)[moduleName as any] + const _module = await defineModule + const getMeta = await _module.getMeta?.() + if (!getMeta) + throw new Error(`Module ${moduleName} does not have meta`) + + const _waitModule = typeof getMeta?.waitModule === 'function' ? await getMeta.waitModule?.(rootOptions) : getMeta?.waitModule + + if (_waitModule) + return _waitModule +} + +function smartSortModules(projectName: string, modules: PrepareModules): string[] { + const sortedModules: string[] = [] + const visited: Set = new Set() + const visiting: Set = new Set() + + const visitModule = (moduleName: string) => { + if (visiting.has(moduleName)) + throw new CircularDependencyError(`Circular dependency detected involving module: ${moduleName}`) + + if (!visited.has(moduleName)) { + visiting.add(moduleName) + + const module = modules[projectName][moduleName] + + if (module && module.waitModule) { + for (const dependency of module.waitModule) + visitModule(dependency) + } + + sortedModules.push(moduleName) + visited.add(moduleName) + visiting.delete(moduleName) + } + } + + for (const moduleName in modules[projectName]) + visitModule(moduleName) + + return sortedModules +} export async function setupModules(data: { resolver: Resolver nuxt: Nuxt }) { const projects = data.nuxt._pergel.rootOptions.projects - const modulesMap = new Map>() - - for await (const [projectKey, modules] of Object.entries(projects)) { - for await (const [moduleKey, moduleValue] of Object.entries(modules)) { - if (typeof moduleValue === 'boolean' && moduleValue === false) - continue - - if ( - (typeof moduleValue === 'object' && moduleValue === null) - || (typeof moduleValue === 'object' && !moduleValue) - ) - continue - - if (typeof moduleValue === 'string' && moduleValue === '') - continue - modulesMap.set(`${projectKey}/${moduleKey}`, moduleValue as any) - } - } + const _projects = projects && Object.values(projects).map(project => Object.keys(project)).flat() + if (!projects || !(_projects.length > 0)) + return - const modulesArray = Array.from(modulesMap) - - data.nuxt._pergel.contents = [] - - for await (const m of modulesArray) { - const [projectName, moduleName] = m[0].split('/') as [string, ModuleName] - // TODO: fix any type - // @ts-ignore - data.nuxt._pergel.projects[projectName] ??= {} - data.nuxt._pergel.projects[projectName][moduleName] = { - projectDir: join(data.nuxt._pergel.pergelDir, projectName), - moduleDir: join(data.nuxt._pergel.pergelDir, projectName, moduleName), - dir: { - project: join(data.nuxt._pergel.dir.pergel, projectName), - module: join(data.nuxt._pergel.dir.pergel, projectName, moduleName), - root: join(data.nuxt._pergel.dir.pergel), - }, - options: {}, - } + const prepareModules = await initModules(data.nuxt, data.resolver) - data.nuxt._pergel._module = { - ...data.nuxt._pergel.projects[projectName][moduleName], - projectName, - moduleName, + for await (const [projectName, _modules] of Object.entries(projects)) { + const sortedModules = smartSortModules(projectName, prepareModules) + + if (data.nuxt._pergel.debug) { + consola.info(`Project ${projectName} modules:`) + consola.info(sortedModules) } - const selectedModule = data.nuxt._pergel.modules.find(module => module === moduleName) - if (Array.isArray(m) && selectedModule) { - let pergelModule: PergelModule + for await (const moduleName of sortedModules) { + const module = (data.nuxt._pergel.projects[projectName as any] as any)[moduleName as any] + const moduleSetup = prepareModules[projectName][moduleName] - try { - const getIndexExt = () => { - const datas = readdirSync(data.resolver.resolve(join('runtime', 'modules', moduleName))) - const indexExt = datas.find(file => file.includes('index') && !file.includes('.d.')) - if (!indexExt) - throw new Error(`Module ${moduleName} does not have index file`) + const getMeta = typeof moduleSetup.defineModule.getMeta === 'function' ? await moduleSetup.defineModule.getMeta() : await moduleSetup.defineModule.getMeta - return indexExt - } - const indexPath = getIndexExt() + if (!getMeta) + throw new Error(`Module ${moduleName} does not have meta`) - pergelModule = await import( - data.resolver.resolve(join('runtime', 'modules', moduleName, indexPath)) - ).then(m => m.default).catch((res) => { - consola.error(`Module ${moduleName} failed to import`) - consola.error(res) + const dependencies = getMeta.dependencies instanceof Function ? getMeta.dependencies(module) : getMeta.dependencies ?? {} + const devDependencies = getMeta.devDependencies instanceof Function ? getMeta.devDependencies(module) : getMeta.devDependencies ?? {} + + if (Object.keys(dependencies).length > 0 || Object.keys(devDependencies).length > 0) { + generateProjectReadme({ + data: ({ addCommentBlock }) => ({ + ...addCommentBlock('If pergel cli is installed, you can run `pergel install` automatically to install'), + packageJson: { + dependencies: `"${Object.entries(dependencies).map(([name, version]) => `${name}@${version}`).join(', ')}"`, + devDependencies: `"${Object.entries(devDependencies).map(([name, version]) => `${name}@${version}`).join(', ')}"`, + }, + }), + moduleName, + nuxt: data.nuxt, + projectName, }) } - catch (error) { - consola.error(`Module ${moduleName} failed to import`) - throw error - } // Throw error if input is not a function - if (typeof pergelModule !== 'function') - throw new TypeError(`Nuxt module should be a function: ${pergelModule}`) + if (typeof moduleSetup.defineModule !== 'function') + throw new TypeError(`Nuxt module should be a function: ${moduleSetup.defineModule}`) - const resolvedModule = await pergelModule({ nuxt: data.nuxt }) + const resolvedModule = await moduleSetup.defineModule({ + nuxt: data.nuxt, + options: {}, + rootOptions: module, + moduleOptions: { + dir: { + module: join(data.nuxt._pergel.dir.pergel, projectName, moduleName), + project: join(data.nuxt._pergel.dir.pergel, projectName), + root: join(data.nuxt._pergel.dir.pergel), + }, + moduleName: moduleName as ModuleName, + projectName, + moduleDir: resolve(data.nuxt._pergel.pergelDir, projectName, moduleName), + }, + }) if (resolvedModule === false /* setup aborted */ || resolvedModule === undefined /* setup failed */ || typeof resolvedModule === 'string' /* setup failed */) { - consola.error(`Module ${moduleName} failed to setup`) - continue + consola.error(`Module ${ + moduleName + } failed to setup`) + return 'continue' } } } diff --git a/packages/nuxt/src/runtime/core/setupPergel.ts b/packages/nuxt/src/runtime/core/setupPergel.ts index 655c697b..476f2d9c 100644 --- a/packages/nuxt/src/runtime/core/setupPergel.ts +++ b/packages/nuxt/src/runtime/core/setupPergel.ts @@ -15,7 +15,6 @@ export async function setupPergel( }, ) { const { options, nuxt, resolver, version } = data - const _options = Object.assign({}, options) const rootDir = options.rootDir ? options.rootDir : './' const pergelDir = join(rootDir, options.pergelDir ?? 'pergel') @@ -51,23 +50,16 @@ export async function setupPergel( nuxt.options.nitro.alias ??= {} nuxt.options.nitro.alias['#pergel/types'] = pergelType.dst - const resolvedOptions = defu(options, { - projects: { - }, - esnext: true, - pergelDir, - rootDir, - } as PergelOptions) + // const resolvedOptions = defu(options, { + // projects: { + // }, + // esnext: true, + // pergelDir, + // rootDir, + // } as PergelOptions) - const resolvedPergelOptions = defu({}, { - nitroImports: {}, - nuxtImports: {}, - readmeYaml: { - pergel: { - 'comment-block-1': 'This file is generated by pergel. Do not edit it manually.', - 'comment-block-2': `Version: ${version}`, - }, - }, + const resolvedPergelOptions = defu(options, { + rootOptions: options, // Pergel Modules modules: [ 'S3', @@ -78,36 +70,31 @@ export async function setupPergel( 'graphqlYoga', 'drizzle', ], + projectNames, + nitroImports: {}, + nuxtImports: {}, + readmeYaml: { + pergel: { + 'comment-block-1': 'This file is generated by pergel. Do not edit it manually.', + 'comment-block-2': `Version: ${version}`, + }, + }, resolver, + devServerHandler: [], + dts: {}, + activeModules: {}, + projects: {}, dir: { - pergel: resolvedOptions.pergelDir ?? 'pergel', + pergel: pergelDir ?? 'pergel', readme: join('pergel', 'README.yaml'), root: options.rootDir ?? './', }, + contents: [], + pergelDir: resolve(resolveDir, pergelDir ?? 'pergel'), rootDir: resolveDir, - pergelDir: resolve(resolveDir, resolvedOptions.pergelDir ?? 'pergel'), readmeDir: resolve(resolveReadmePath), - projectNames, - rootOptions: _options, - projects: {}, - activeModules: {}, - contents: [], - devServerHandler: [], - dts: {}, esnext: true, - _module: { - dir: { - module: '', - project: '', - root: '', - }, - moduleDir: '', - moduleName: '', - options: {}, - projectDir: '', - projectName: '', - }, - } as ResolvedPergelOptions) - - nuxt._pergel = resolvedPergelOptions + debug: false, + } satisfies ResolvedPergelOptions) + nuxt._pergel = resolvedPergelOptions as any } diff --git a/packages/nuxt/src/runtime/core/types/module.ts b/packages/nuxt/src/runtime/core/types/module.ts index bbbbc738..8bd3704d 100644 --- a/packages/nuxt/src/runtime/core/types/module.ts +++ b/packages/nuxt/src/runtime/core/types/module.ts @@ -7,8 +7,8 @@ import type { ImportsOptions, Nuxt } from '@nuxt/schema' import type { Resolver } from '@nuxt/kit' import type { UnimportPluginOptions } from 'unimport/unplugin' -import type { GraphQLYogaConfig } from '../../modules/graphqlYoga/types' -import type { DrizzleConfig } from '../../modules/drizzle/types' +import type { GraphQLYogaConfig, ResolvedGraphQLYogaConfig } from '../../modules/graphqlYoga/types' +import type { DrizzleConfig, ResolvedDrizzleConfig } from '../../modules/drizzle/types' export type { ResolvedGraphQLYogaConfig } from '../../modules/graphqlYoga/types' @@ -22,6 +22,16 @@ export interface Modules { drizzle?: true | DrizzleConfig } +export interface ResolvedModules { + S3?: true + ses?: true + nodeCron?: true + bullmq?: true + json2csv?: true + graphqlYoga?: ResolvedGraphQLYogaConfig + drizzle?: ResolvedDrizzleConfig +} + export type ModuleName = keyof Modules export interface PergelOptions { @@ -58,13 +68,19 @@ export interface PergelOptions { * @default true */ esnext?: boolean + + /** + * @default false + */ + debug?: true } -export interface ResolvedPergelOptions { +export interface ResolvedPergelOptions { /** * Pergel user defined options. */ - rootOptions: Required + rootOptions: PergelOptions + /** * [S3, nodecron, graphql, drizzle] */ @@ -92,6 +108,7 @@ export interface ResolvedPergelOptions } } } + activeModules: { [projectName: string]: { [moduleName: string]: { @@ -103,42 +120,37 @@ export interface ResolvedPergelOptions } projects: { - [project: string]: { - [module in ModuleName]: { - options: T + [project: string]: ResolvedModules & { + /** + * @example + * 'users/productdevbook/nuxt3/pergel/${projectName}' + */ + projectDir: string + /** + * @example + * 'users/productdevbook/nuxt3/pergel/${projectName}/${moduleName}' + */ + moduleDir: string + + dir: { /** * @example - * 'users/productdevbook/nuxt3/pergel/${projectName}' + * 'pergel/${projectName}' */ - projectDir: string + project: string + /** * @example - * 'users/productdevbook/nuxt3/pergel/${projectName}/${moduleName}' + * 'pergel/${projectName}/${moduleName}' */ - moduleDir: string - - dir: { - - /** - * @example - * 'pergel/${projectName}' - */ - project: string - - /** - * @example - * 'pergel/${projectName}/${moduleName}' - */ - module: string - - /** - * @example - * 'pergel' - */ - root: string - } + module: string + /** + * @example + * 'pergel' + */ + root: string } } } @@ -163,11 +175,6 @@ export interface ResolvedPergelOptions readme: string } - _module: ResolvedPergelOptions['projects'][string][ModuleName] & { - projectName: string - moduleName: string - } - contents: { projectName: string moduleName: string @@ -192,13 +199,28 @@ export interface ResolvedPergelOptions * 'users/productdevbook/nuxt3/pergel' */ pergelDir: string + + esnext: boolean + + debug: boolean } -export interface NuxtPergel extends Nuxt { - _pergel: ResolvedPergelOptions +export interface NuxtPergel extends Nuxt { + _pergel: ResolvedPergelOptions } -interface ModuleMeta { +export interface ResolvedModuleOptions { + dir: { + module: string + project: string + root: string + } + moduleName: string + projectName: string + moduleDir: string +} + +interface ModuleMeta { /** Module name. */ name?: string /** Module version. */ @@ -209,10 +231,12 @@ interface ModuleMeta { */ configKey?: string - devDependencies?: Record | ((options: T) => Record) - dependencies?: Record | ((options: T) => Record) + devDependencies?: Record | ((options: RootOptions) => Record) + dependencies?: Record | ((options: RootOptions) => Record) dts?: boolean + waitModule?: ModuleName[] | ((options: RootOptions) => ModuleName[]) + [key: string]: unknown } @@ -234,19 +258,37 @@ export interface ModuleSetupReturn { export type Awaitable = T | Promise type _ModuleSetupReturn = Awaitable -export interface ModuleDefinition { - meta?: ModuleMeta - defaults?: T | ((data: { nuxt: NuxtPergel }) => T) +export interface ModuleDefinition { + meta?: ModuleMeta + defaults?: ResolvedOptions + | ((data: { + nuxt: NuxtPergel + rootOptions: RootOptions + moduleOptions: ResolvedModuleOptions + }) + => ResolvedOptions) setup?: ( this: void, - data: { nuxt: NuxtPergel } + data: { + nuxt: NuxtPergel + options: ResolvedOptions + rootOptions: RootOptions + moduleOptions: ResolvedModuleOptions + } ) => _ModuleSetupReturn } -export interface PergelModule { - (this: void, data: { nuxt: NuxtPergel }): _ModuleSetupReturn - getOptions?: (inlineOptions?: T, data?: { nuxt: NuxtPergel }) => Promise +export interface PergelModule { + (this: void, data: { + nuxt: NuxtPergel + options: ResolvedOptions + rootOptions: RootOptions + moduleOptions: ResolvedModuleOptions + }): _ModuleSetupReturn + getOptions?: ( + inlineOptions?: ResolvedOptions, + data?: { nuxt: NuxtPergel, rootOptions: RootOptions }) => Promise getMeta?: () => ModuleMeta } diff --git a/packages/nuxt/src/runtime/core/utils/addModuleDTS.ts b/packages/nuxt/src/runtime/core/utils/addModuleDTS.ts index d19d836e..fff08cd0 100644 --- a/packages/nuxt/src/runtime/core/utils/addModuleDTS.ts +++ b/packages/nuxt/src/runtime/core/utils/addModuleDTS.ts @@ -1,5 +1,6 @@ import { existsSync, mkdirSync, writeFileSync } from 'node:fs' import type { Nuxt } from '@nuxt/schema' +import type { ResolvedModuleOptions } from '../types' export function addModuleDTS(data: { template: string @@ -7,6 +8,7 @@ export function addModuleDTS(data: { moduleName: string interfaceNames: string[] nuxt: Nuxt + moduleOptions: ResolvedModuleOptions }) { data.nuxt._pergel.dts[data.projectName] ??= {} data.nuxt._pergel.dts[data.projectName][data.moduleName] ??= { @@ -16,8 +18,8 @@ export function addModuleDTS(data: { data.nuxt._pergel.dts[data.projectName][data.moduleName].interfaceNames.push(...data.interfaceNames) data.nuxt._pergel.dts[data.projectName][data.moduleName].template.push(data.template) - if (!existsSync(data.nuxt._pergel._module.moduleDir)) - mkdirSync(data.nuxt._pergel._module.moduleDir, { recursive: true }) + if (!existsSync(data.moduleOptions.moduleDir)) + mkdirSync(data.moduleOptions.moduleDir, { recursive: true }) const body = /* ts */` declare module 'pergel/${data.projectName}/types' { @@ -25,13 +27,13 @@ declare module 'pergel/${data.projectName}/types' { } `.trim() - if (!existsSync(`${data.nuxt._pergel._module.moduleDir}/index.d.ts`)) { + if (!existsSync(`${data.moduleOptions.moduleDir}/index.d.ts`)) { writeFileSync( - `${data.nuxt._pergel._module.moduleDir}/index.d.ts`, + `${data.moduleOptions.moduleDir}/index.d.ts`, body, ) } return { - path: `${data.nuxt._pergel._module.moduleDir}/index.d.ts`, + path: `${data.moduleOptions.moduleDir}/index.d.ts`, } } diff --git a/packages/nuxt/src/runtime/core/utils/generateYaml.ts b/packages/nuxt/src/runtime/core/utils/generateYaml.ts index 1ec95654..1b8ddf59 100644 --- a/packages/nuxt/src/runtime/core/utils/generateYaml.ts +++ b/packages/nuxt/src/runtime/core/utils/generateYaml.ts @@ -47,31 +47,32 @@ export function generateReadmeYaml(data: { writeFileSync(data.nuxt._pergel.readmeDir, jsonToYaml(readmeYaml)) } -export function generateProjectReadme( - nuxt: NuxtPergel, +export function generateProjectReadme(input: +{ + nuxt: NuxtPergel + projectName: string + moduleName: string data: ( ctx: { addCommentBlock: (commentBlock: string) => Record moduleName: string } - ) => Record, - customName?: string, + ) => Record +}, ) { - const projectName = nuxt._pergel._module.projectName - const moduleName = customName || nuxt._pergel._module.moduleName const uuid = () => Math.random().toString(36).substring(7) const addCommentBlock = (commentBlock: string) => ({ [`comment-block-${uuid()}`]: commentBlock, }) - nuxt._pergel.readmeYaml[projectName] = defu(nuxt._pergel.readmeYaml[projectName], { - [moduleName]: { + input.nuxt._pergel.readmeYaml[input.projectName] = defu(input.nuxt._pergel.readmeYaml[input.projectName], { + [input.moduleName]: { // [`comment-block-${uuid()}`]: `${moduleName} Variables`, - ...data( + ...input.data( { addCommentBlock, - moduleName, + moduleName: input.moduleName, }, ), }, diff --git a/packages/nuxt/src/runtime/core/utils/index.ts b/packages/nuxt/src/runtime/core/utils/index.ts index 6563e2d4..cf66d59f 100644 --- a/packages/nuxt/src/runtime/core/utils/index.ts +++ b/packages/nuxt/src/runtime/core/utils/index.ts @@ -1,6 +1,6 @@ import { snakeCase } from 'scule' import type { EnvList } from '../types' - +export { useModuleOptions } from './useModuleOptions' /** * Reformat source code for improved readability by adding appropriate newlines and indentation. */ diff --git a/packages/nuxt/src/runtime/core/utils/moduleRuntimeConfig.ts b/packages/nuxt/src/runtime/core/utils/moduleRuntimeConfig.ts index 65e8863b..f164e847 100644 --- a/packages/nuxt/src/runtime/core/utils/moduleRuntimeConfig.ts +++ b/packages/nuxt/src/runtime/core/utils/moduleRuntimeConfig.ts @@ -1,16 +1,17 @@ import defu from 'defu' import { addTemplate } from '@nuxt/kit' -import type { NuxtPergel } from '../types' +import type { NuxtPergel, ResolvedModuleOptions } from '../types' import { generateProjectName, runtimeConfigToEnv } from '.' export function generateModuleRuntimeConfig( nuxt: NuxtPergel, + moduleOptions: ResolvedModuleOptions, config: Record, publicRuntime?: boolean, customName?: string, ) { - const projectName = nuxt._pergel._module.projectName - const moduleName = nuxt._pergel._module.moduleName + const projectName = moduleOptions.projectName + const moduleName = moduleOptions.moduleName const runtimeConfig = nuxt.options.runtimeConfig @@ -44,6 +45,8 @@ export function generateModuleRuntimeConfig( const { envs, keyEnvValue } = runtimeConfigToEnv(runtimeConfig[name as any] as any, [name]) + nuxt._pergel.readmeYaml[projectName] ??= {} + nuxt._pergel.readmeYaml[projectName][moduleName] ??= {} nuxt._pergel.readmeYaml[projectName][moduleName] = defu(nuxt._pergel.readmeYaml[projectName][moduleName], { ...customName ? { diff --git a/packages/nuxt/src/runtime/core/utils/useModuleOptions.ts b/packages/nuxt/src/runtime/core/utils/useModuleOptions.ts new file mode 100644 index 00000000..a55d1547 --- /dev/null +++ b/packages/nuxt/src/runtime/core/utils/useModuleOptions.ts @@ -0,0 +1,15 @@ +import type { NuxtPergel, ResolvedModuleOptions } from '../types' + +export function useModuleOptions( + nuxt: NuxtPergel, + moduleOptions: ResolvedModuleOptions, +) { + const { moduleName, projectName } = moduleOptions + const resolvedOptions = (nuxt._pergel.projects[projectName as any] as any)[moduleName as any] as ResolvedOptions + const rootOptions = (nuxt._pergel.rootOptions.projects[projectName as any] as any)[moduleName] as Options + + return { + rootOptions, + resolvedOptions, + } +} diff --git a/packages/nuxt/src/runtime/modules/S3/index.ts b/packages/nuxt/src/runtime/modules/S3/index.ts index 9727af01..b130cb9f 100644 --- a/packages/nuxt/src/runtime/modules/S3/index.ts +++ b/packages/nuxt/src/runtime/modules/S3/index.ts @@ -11,11 +11,10 @@ export default definePergelModule({ '@pergel/module-s3': '0.0.0', }, }, - setup({ nuxt }) { + setup({ nuxt, moduleOptions }) { const resolver = createResolver(import.meta.url) - const module = nuxt._pergel._module - generateModuleRuntimeConfig(nuxt, { + generateModuleRuntimeConfig(nuxt, moduleOptions, { region: 'auto', endpoint: '', accessKeyId: '', @@ -39,8 +38,8 @@ export default definePergelModule({ } nuxt._pergel.contents.push({ - moduleName: module.moduleName, - projectName: module.projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* TypeScript */ ` function S3() { return { diff --git a/packages/nuxt/src/runtime/modules/bullmq/export.ts b/packages/nuxt/src/runtime/modules/bullmq/export.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/nuxt/src/runtime/modules/bullmq/index.ts b/packages/nuxt/src/runtime/modules/bullmq/index.ts index c89f6416..c4e20e7f 100644 --- a/packages/nuxt/src/runtime/modules/bullmq/index.ts +++ b/packages/nuxt/src/runtime/modules/bullmq/index.ts @@ -16,12 +16,10 @@ export default definePergelModule({ dts: true, }, defaults: {}, - async setup({ nuxt }) { - const options = nuxt._pergel._module - + async setup({ nuxt, moduleOptions }) { const resolver = createResolver(import.meta.url) - generateModuleRuntimeConfig(nuxt, { + generateModuleRuntimeConfig(nuxt, moduleOptions, { options: { host: '', port: 6379, @@ -41,14 +39,15 @@ export interface BullmqContext { } `, nuxt, - moduleName: options.moduleName, - projectName: options.projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, interfaceNames: ['BullmqContext'], + moduleOptions, }) nuxt._pergel.contents.push({ - moduleName: options.moduleName, - projectName: options.projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function bullmq() { return { diff --git a/packages/nuxt/src/runtime/modules/drizzle/core.ts b/packages/nuxt/src/runtime/modules/drizzle/core.ts index e063b408..6db8d6f3 100644 --- a/packages/nuxt/src/runtime/modules/drizzle/core.ts +++ b/packages/nuxt/src/runtime/modules/drizzle/core.ts @@ -3,10 +3,9 @@ import { resolve } from 'node:path' import { useLogger } from '@nuxt/kit' import { consola } from 'consola' import type { NuxtPergel } from '../../core/types' -import type { ResolvedDrizzleConfig } from './types' export async function copyMigrationFolder( - nuxt: NuxtPergel, + nuxt: NuxtPergel, ) { /** * Public Assets diff --git a/packages/nuxt/src/runtime/modules/drizzle/drivers/postgres/index.ts b/packages/nuxt/src/runtime/modules/drizzle/drivers/postgres/index.ts index 1f5a66db..52714818 100644 --- a/packages/nuxt/src/runtime/modules/drizzle/drivers/postgres/index.ts +++ b/packages/nuxt/src/runtime/modules/drizzle/drivers/postgres/index.ts @@ -4,17 +4,20 @@ import { startSubprocess } from '@nuxt/devtools-kit' import type { ResolvedDrizzleConfig } from '../../types' import { createDrizzleConfig } from '../../defaults/postgresjs' -import type { NuxtPergel } from '../../../../core/types' +import type { NuxtPergel, ResolvedModuleOptions } from '../../../../core/types' import { generateModuleRuntimeConfig } from '../../../../core/utils/moduleRuntimeConfig' import { generateProjectReadme } from '../../../../core/utils/generateYaml' -export async function setupPostgres(nuxt: NuxtPergel) { - const module = nuxt._pergel._module - const projectName = module.projectName - const moduleName = module.moduleName - const { driver } = module.options._driver +export async function setupPostgres( + nuxt: NuxtPergel, + options: ResolvedDrizzleConfig, + moduleOptions: ResolvedModuleOptions, +) { + const projectName = moduleOptions.projectName + const moduleName = moduleOptions.moduleName + const { driver } = options._driver - const { env } = generateModuleRuntimeConfig(nuxt, { + const { env } = generateModuleRuntimeConfig(nuxt, moduleOptions, { url: '', host: '', // Postgres ip address[s] or domain name[s] port: 5432, // Postgres server port[s] @@ -31,8 +34,8 @@ export async function setupPostgres(nuxt: NuxtPergel) { /** @type { import("drizzle-kit").Config } */ export default { - schema: '${nuxt._pergel._module.dir.module}/schema/index.ts', - out: '${nuxt._pergel._module.dir.module}/migrations', + schema: '${moduleOptions.dir.module}/schema/index.ts', + out: '${moduleOptions.dir.module}/migrations', ${driver === 'pg' ? `driver: '${driver}',` : ''} dbCredentials: process.env.${env.url} ? { @@ -49,21 +52,21 @@ export default { } ` - if (!existsSync(nuxt._pergel._module.moduleDir)) - mkdirSync(nuxt._pergel._module.moduleDir, { recursive: true, mode: 0o777 }) + if (!existsSync(moduleOptions.moduleDir)) + mkdirSync(moduleOptions.moduleDir, { recursive: true, mode: 0o777 }) - if (!existsSync(resolve(nuxt._pergel._module.moduleDir, 'drizzle.config.js'))) { - writeFileSync(resolve(nuxt._pergel._module.moduleDir, 'drizzle.config.js'), drizzleConfig, { + if (!existsSync(resolve(moduleOptions.moduleDir, 'drizzle.config.js'))) { + writeFileSync(resolve(moduleOptions.moduleDir, 'drizzle.config.js'), drizzleConfig, { mode: 0o777, encoding: 'utf8', }) } // Seed generation - if (!existsSync(resolve(nuxt._pergel._module.options.seedPaths))) - mkdirSync(resolve(nuxt._pergel._module.moduleDir, 'seeds'), { recursive: true, mode: 0o777 }) + if (!existsSync(resolve(options.seedPaths))) + mkdirSync(resolve(moduleOptions.moduleDir, 'seeds'), { recursive: true, mode: 0o777 }) - if (!existsSync(resolve(nuxt._pergel._module.options.seedPaths, 'index.ts'))) { + if (!existsSync(resolve(options.seedPaths, 'index.ts'))) { const readFile = await import('./seed').then(m => m.default).catch(() => null) if (readFile) { const file = readFile({ @@ -72,29 +75,29 @@ export default { dbDrop: env.drop, dbSeed: env.seed, }, - migrationDir: join(nuxt._pergel._module.dir.module, nuxt._pergel._module.options.dir.migrations), + migrationDir: join(moduleOptions.dir.module, options.dir.migrations), }) - writeFileSync(resolve(nuxt._pergel._module.options.seedPaths, 'index.ts'), file, { + writeFileSync(resolve(options.seedPaths, 'index.ts'), file, { mode: 0o777, encoding: 'utf8', }) } } - if (!existsSync(resolve(nuxt._pergel._module.options.seedPaths, 'seeds', 'seed1.ts'))) { + if (!existsSync(resolve(options.seedPaths, 'seeds', 'seed1.ts'))) { const readFile = await import('./seed/s-seed1').then(m => m.default).catch(() => null) if (readFile) { const file = readFile() - writeFileSync(resolve(nuxt._pergel._module.options.seedPaths, 'seed1.ts'), file) + writeFileSync(resolve(options.seedPaths, 'seed1.ts'), file) } } - createDrizzleConfig({ schemaPath: nuxt._pergel._module.options.schemaPath }) + createDrizzleConfig({ schemaPath: options.schemaPath }) if (nuxt.options.dev) { const subprocess = startSubprocess({ command: 'drizzle-kit', - args: ['studio', '--port', '3105', `--config=${nuxt._pergel._module.moduleDir}/drizzle.config.js`], + args: ['studio', '--port', '3105', `--config=${moduleOptions.moduleDir}/drizzle.config.js`], cwd: nuxt.options.rootDir, env: { ...process.env, @@ -114,25 +117,30 @@ export default { }) } - generateProjectReadme(nuxt, ({ addCommentBlock }) => ({ - ...addCommentBlock('Script Commands'), - scripts: { - migrate: `drizzle-kit generate:${driver} --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - generate: `drizzle-kit generate:${driver} --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - push: `drizzle-kit push:${driver} --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - drop: `drizzle-kit drop --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - up: `drizzle-kit up:${driver} --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - studio: `drizzle-kit studio --port 3105 --config=${nuxt._pergel._module.dir.module}/drizzle.config.js`, - seed: `tsx ${nuxt._pergel._module.dir.module}/seeds/index.ts`, - }, - cli: { - migrate: `pergel module -s=migrate -p=${projectName} -m=${moduleName}`, - push: `pergel module -s=push -p=${projectName} -m=${moduleName}`, - drop: `pergel module -s=drop -p=${projectName} -m=${moduleName}`, - up: `pergel module -s=up -p=${projectName} -m=${moduleName}`, - generate: `pergel module -s=generate -p=${projectName} -m=${moduleName}`, - studio: `pergel module -s=studio -p=${projectName} -m=${moduleName}`, - seed: `pergel module -s=seed -p=${projectName} -m=${moduleName}`, - }, - })) + generateProjectReadme({ + data: ({ addCommentBlock }) => ({ + ...addCommentBlock('Script Commands'), + scripts: { + migrate: `drizzle-kit generate:${driver} --config=${moduleOptions.dir.module}/drizzle.config.js`, + generate: `drizzle-kit generate:${driver} --config=${moduleOptions.dir.module}/drizzle.config.js`, + push: `drizzle-kit push:${driver} --config=${moduleOptions.dir.module}/drizzle.config.js`, + drop: `drizzle-kit drop --config=${moduleOptions.dir.module}/drizzle.config.js`, + up: `drizzle-kit up:${driver} --config=${moduleOptions.dir.module}/drizzle.config.js`, + studio: `drizzle-kit studio --port 3105 --config=${moduleOptions.dir.module}/drizzle.config.js`, + seed: `tsx ${moduleOptions.dir.module}/seeds/index.ts`, + }, + cli: { + migrate: `pergel module -s=migrate -p=${projectName} -m=${moduleName}`, + push: `pergel module -s=push -p=${projectName} -m=${moduleName}`, + drop: `pergel module -s=drop -p=${projectName} -m=${moduleName}`, + up: `pergel module -s=up -p=${projectName} -m=${moduleName}`, + generate: `pergel module -s=generate -p=${projectName} -m=${moduleName}`, + studio: `pergel module -s=studio -p=${projectName} -m=${moduleName}`, + seed: `pergel module -s=seed -p=${projectName} -m=${moduleName}`, + }, + }), + nuxt, + moduleName, + projectName, + }) } diff --git a/packages/nuxt/src/runtime/modules/drizzle/index.ts b/packages/nuxt/src/runtime/modules/drizzle/index.ts index ca533d44..a78c218b 100644 --- a/packages/nuxt/src/runtime/modules/drizzle/index.ts +++ b/packages/nuxt/src/runtime/modules/drizzle/index.ts @@ -12,7 +12,7 @@ import { copyMigrationFolder } from './core' const _logger = useLogger('pergel:drizzle') -export default definePergelModule({ +export default definePergelModule({ meta: { name: 'drizzle', version: '0.0.1', @@ -42,16 +42,14 @@ export default definePergelModule({ return data }, }, - defaults({ nuxt }) { - const rootOptions = nuxt._pergel._module.options - + defaults({ rootOptions, moduleOptions }) { const [driverName, driver] = rootOptions.driver?.split(':') ?? ['postgresjs', 'pg'] return { driver: rootOptions.driver ?? 'postgresjs:pg', - migrationsPath: resolve(nuxt._pergel._module.moduleDir, rootOptions.migrationsPath ?? 'migrations'), - schemaPath: resolve(nuxt._pergel._module.moduleDir, rootOptions.schemaPath ?? 'schema'), - seedPaths: resolve(nuxt._pergel._module.moduleDir, rootOptions.seedPaths ?? 'seeds'), + migrationsPath: resolve(moduleOptions.moduleDir, rootOptions.migrationsPath ?? 'migrations'), + schemaPath: resolve(moduleOptions.moduleDir, rootOptions.schemaPath ?? 'schema'), + seedPaths: resolve(moduleOptions.moduleDir, rootOptions.seedPaths ?? 'seeds'), mergeSchemas: false, dir: { schema: rootOptions.schemaPath ?? 'schema', @@ -64,36 +62,34 @@ export default definePergelModule({ studio: true, } }, - async setup({ nuxt }) { - const projectName = nuxt._pergel._module.projectName - const moduleOptions = nuxt._pergel._module + async setup({ nuxt, options, moduleOptions }) { const resolver = createResolver(import.meta.url) - if (!existsSync(moduleOptions.options.schemaPath)) - mkdirSync(moduleOptions.options.schemaPath, { recursive: true }) + if (!existsSync(options.schemaPath)) + mkdirSync(options.schemaPath, { recursive: true }) - if (!existsSync(moduleOptions.options.migrationsPath)) - mkdirSync(moduleOptions.options.migrationsPath, { recursive: true }) + if (!existsSync(options.migrationsPath)) + mkdirSync(options.migrationsPath, { recursive: true }) - if (!existsSync(moduleOptions.options.seedPaths)) - mkdirSync(moduleOptions.options.seedPaths, { recursive: true }) + if (!existsSync(options.seedPaths)) + mkdirSync(options.seedPaths, { recursive: true }) // Driver setup - switch (moduleOptions.options._driver.name) { + switch (options._driver.name) { case 'postgresjs': - await setupPostgres(nuxt) + await setupPostgres(nuxt, options, moduleOptions) break } - nuxt.options.alias[`${projectName}/drizzle/schema`] = resolve( + nuxt.options.alias[`${moduleOptions.projectName}/drizzle/schema`] = resolve( nuxt.options.rootDir, - moduleOptions.options.schemaPath, + options.schemaPath, ) nuxt.options.nitro.alias ??= {} - nuxt.options.nitro.alias[`${projectName}/drizzle/schema`] = resolve( + nuxt.options.nitro.alias[`${moduleOptions.projectName}/drizzle/schema`] = resolve( nuxt.options.rootDir, - moduleOptions.options.schemaPath, + options.schemaPath, ) addImportsDir(resolver.resolve('./drivers/postgres')) @@ -102,10 +98,10 @@ export default definePergelModule({ useNitroImports(nuxt, { presets: [ { - from: `${nuxt._pergel._module.options.schemaPath}`, + from: `${options.schemaPath}`, imports: [ { - as: `tables${pascalCase(projectName)}`, + as: `tables${pascalCase(moduleOptions.projectName)}`, name: '*', }, ], @@ -139,8 +135,8 @@ export default definePergelModule({ 'sql', ].map(name => ({ name, - as: moduleOptions.options.autoImportPrefix?.filters - ? `${moduleOptions.options.autoImportPrefix?.filters}${name}` + as: options.autoImportPrefix?.filters + ? `${options.autoImportPrefix?.filters}${name}` : name, priority: 1, meta: { @@ -155,7 +151,7 @@ export default definePergelModule({ copyMigrationFolder(nuxt) const returnDriver = /* ts */` - ${camelCase(moduleOptions.options._driver.name ?? 'postgresjs')}() { + ${camelCase(options._driver.name ?? 'postgresjs')}() { return { connect: connectPostgresJS.bind(ctx), } @@ -193,13 +189,13 @@ export default definePergelModule({ }) nuxt._pergel.contents.push({ - moduleName: 'drizzle', - projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function drizzle() { return { ${returnDriver} - schema: tables${pascalCase(projectName)}, + schema: tables${pascalCase(moduleOptions.projectName)}, } } `, diff --git a/packages/nuxt/src/runtime/modules/drizzle/types.ts b/packages/nuxt/src/runtime/modules/drizzle/types.ts index f1b08f39..30f6c91b 100644 --- a/packages/nuxt/src/runtime/modules/drizzle/types.ts +++ b/packages/nuxt/src/runtime/modules/drizzle/types.ts @@ -21,6 +21,11 @@ export interface DrizzleConfig { */ migrationsPath?: string + /** + * Database seeds + * @default 'pergel/{projectName}/{moduleName}/seeds' + */ + seedPaths?: string /** * Merge schemas * @default true diff --git a/packages/nuxt/src/runtime/modules/graphqlYoga/index.ts b/packages/nuxt/src/runtime/modules/graphqlYoga/index.ts index a5dab558..67eec8e7 100644 --- a/packages/nuxt/src/runtime/modules/graphqlYoga/index.ts +++ b/packages/nuxt/src/runtime/modules/graphqlYoga/index.ts @@ -5,12 +5,12 @@ import { pascalCase } from 'scule' import { definePergelModule } from '../../core/definePergel' import { useNitroImports } from '../../core/utils/useImports' import { generateModuleRuntimeConfig } from '../../core/utils/moduleRuntimeConfig' -import type { ResolvedGraphQLYogaConfig } from './types' +import type { GraphQLYogaConfig, ResolvedGraphQLYogaConfig } from './types' import { generateGraphQLTemplate } from './utils/generateGraphqlTemplate' // const _logger = useLogger('pergel:graphql:yoga') -export default definePergelModule({ +export default definePergelModule({ meta: { name: 'graphqlYoga', version: '0.0.1', @@ -19,22 +19,20 @@ export default definePergelModule({ }, dts: true, }, - defaults({ nuxt }) { - const options = nuxt._pergel._module.options - - return defu(options, { - documents: resolve(nuxt._pergel._module.moduleDir, options.documents ?? 'documents'), - schema: resolve(nuxt._pergel._module.moduleDir, options.schema ?? 'schema'), + defaults({ rootOptions, moduleOptions }) { + return defu(rootOptions, { + documents: resolve(moduleOptions.moduleDir, rootOptions.documents ?? 'documents'), + schema: resolve(moduleOptions.moduleDir, rootOptions.schema ?? 'schema'), codegen: { client: { extension: '.graphql', onlyDevelopment: true, - configFilePath: resolve(nuxt._pergel._module.moduleDir, options.codegen?.client?.configFilePath ?? 'codegen/client.ts'), + configFilePath: resolve(moduleOptions.moduleDir, rootOptions.codegen?.client?.configFilePath ?? 'codegen/client.ts'), }, server: { extension: '.graphql', onlyDevelopment: true, - configFilePath: resolve(nuxt._pergel._module.moduleDir, options.codegen?.server?.configFilePath ?? 'codegen/server.ts'), + configFilePath: resolve(moduleOptions.moduleDir, rootOptions.codegen?.server?.configFilePath ?? 'codegen/server.ts'), }, }, endpoint: '/api/graphql', @@ -56,20 +54,18 @@ export default definePergelModule({ ready: '/api/graphql/ready', }, mergeSchemas: false, - } as ResolvedGraphQLYogaConfig) + } satisfies ResolvedGraphQLYogaConfig) as ResolvedGraphQLYogaConfig }, - async setup({ nuxt }) { - const module = nuxt._pergel._module - + async setup({ nuxt, options, moduleOptions }) { const resolver = createResolver(import.meta.url) - generateModuleRuntimeConfig(nuxt, { - ...nuxt._pergel._module.options, + generateModuleRuntimeConfig(nuxt, moduleOptions, { + ...options, }, true) addServerImportsDir(resolver.resolve('./composables/**')) - addServerImportsDir(join(nuxt.options.buildDir, 'pergel', module.projectName, module.moduleName, 'client')) + addServerImportsDir(join(nuxt.options.buildDir, 'pergel', moduleOptions.projectName, moduleOptions.moduleName, 'client')) useNitroImports(nuxt, { presets: [ @@ -78,10 +74,10 @@ export default definePergelModule({ imports: ['GraphQLError'], }, { - from: join(nuxt.options.buildDir, 'pergel', module.projectName, module.moduleName, 'client'), + from: join(nuxt.options.buildDir, 'pergel', moduleOptions.projectName, moduleOptions.moduleName, 'client'), imports: [ { - as: `${module.projectName}${pascalCase(module.moduleName)}Document`, + as: `${moduleOptions.projectName}${pascalCase(moduleOptions.moduleName)}Document`, name: '*', }, ], @@ -105,11 +101,13 @@ export default definePergelModule({ generateGraphQLTemplate({ nuxt, + options, + moduleOptions, }) nuxt._pergel.contents.push({ - moduleName: module.moduleName, - projectName: module.projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function graphqlYoga() { return { diff --git a/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateCodegen.ts b/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateCodegen.ts index 21a61594..ff5e3919 100644 --- a/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateCodegen.ts +++ b/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateCodegen.ts @@ -5,7 +5,6 @@ import consola from 'consola' import { buildTime } from '../utils' import type { NuxtPergel } from '../../../core/types' import { useNuxtImports } from '../../../core/utils/useImports' -import type { GraphQLYogaConfig } from '../types' import { useCodegen } from './codegen' export async function loadGraphQLFiles( @@ -49,7 +48,7 @@ export async function useGenerateCodegen({ documentDir, moduleDTS, }: { - nuxt: NuxtPergel + nuxt: NuxtPergel projectName: string moduleDir: string type: 'server' | 'client' | 'all' diff --git a/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateGraphqlTemplate.ts b/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateGraphqlTemplate.ts index a42337be..c1ae9460 100644 --- a/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateGraphqlTemplate.ts +++ b/packages/nuxt/src/runtime/modules/graphqlYoga/utils/generateGraphqlTemplate.ts @@ -1,17 +1,18 @@ import { join, resolve } from 'node:path' import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs' import { relative } from 'pathe' -import type { NuxtPergel } from '../../../core/types' +import type { NuxtPergel, ResolvedModuleOptions } from '../../../core/types' import { matchGlobs } from '../utils' import type { ResolvedGraphQLYogaConfig } from '../types' import { addModuleDTS } from '../../../core/utils/addModuleDTS' import { useGenerateCodegen } from './generateCodegen' export function generateGraphQLTemplate(data: { - nuxt: NuxtPergel + nuxt: NuxtPergel + options: ResolvedGraphQLYogaConfig + moduleOptions: ResolvedModuleOptions }) { - const module = data.nuxt._pergel._module - const { codegen, documents, schema } = module.options + const { codegen, documents, schema } = data.options function globsServerClient(path: string) { const absolutePath = resolve(data.nuxt.options.rootDir, path) @@ -77,22 +78,23 @@ export interface GraphqlYogaContext extends YogaInitialContext { event: H3Event } `, - moduleName: module.moduleName, - projectName: module.projectName, + moduleName: data.moduleOptions.moduleName, + projectName: data.moduleOptions.projectName, nuxt: data.nuxt, interfaceNames: ['GraphqlYogaContext'], + moduleOptions: data.moduleOptions, }) useGenerateCodegen({ nuxt: data.nuxt, type: 'all', - moduleDir: module.dir.module, - projectName: module.projectName, + moduleDir: data.moduleOptions.dir.module, + projectName: data.moduleOptions.projectName, schemaDir: schema, documentDir: documents, moduleDTS: { name: 'GraphqlYogaContext', - path: `pergel/${module.projectName}/types`, + path: `pergel/${data.moduleOptions.projectName}/types`, }, }) @@ -110,7 +112,7 @@ export interface GraphqlYogaContext extends YogaInitialContext { documentDir: documents, moduleDTS: { name: 'GraphqlYogaContext', - path: `pergel/${module.projectName}/types`, + path: `pergel/${data.moduleOptions.projectName}/types`, }, }) } @@ -125,7 +127,7 @@ export interface GraphqlYogaContext extends YogaInitialContext { documentDir: documents, moduleDTS: { name: 'GraphqlYogaContext', - path: `pergel/${module.projectName}/types`, + path: `pergel/${data.moduleOptions.projectName}/types`, }, }) } diff --git a/packages/nuxt/src/runtime/modules/json2csv/index.ts b/packages/nuxt/src/runtime/modules/json2csv/index.ts index 3683df1c..1c0db97d 100644 --- a/packages/nuxt/src/runtime/modules/json2csv/index.ts +++ b/packages/nuxt/src/runtime/modules/json2csv/index.ts @@ -10,16 +10,15 @@ export default definePergelModule({ }, }, defaults: {}, - async setup({ nuxt }) { + async setup({ nuxt, moduleOptions }) { const resolver = createResolver(import.meta.url) - const projectName = nuxt._pergel._module.projectName addServerImportsDir(resolver.resolve('./composables/server')) addImportsDir(resolver.resolve('./composables/vue')) nuxt._pergel.contents.push({ - moduleName: 'json2csv', - projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function json2csv() { return { diff --git a/packages/nuxt/src/runtime/modules/nodeCron/index.ts b/packages/nuxt/src/runtime/modules/nodeCron/index.ts index fe1bc3d0..8417268b 100644 --- a/packages/nuxt/src/runtime/modules/nodeCron/index.ts +++ b/packages/nuxt/src/runtime/modules/nodeCron/index.ts @@ -13,15 +13,14 @@ export default definePergelModule({ }, }, defaults: {}, - async setup({ nuxt }) { + async setup({ nuxt, moduleOptions }) { const resolver = createResolver(import.meta.url) - const projectName = nuxt._pergel._module.projectName addServerImportsDir(resolver.resolve('./composables')) nuxt._pergel.contents.push({ - moduleName: 'nodeCron', - projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function nodeCron() { return { diff --git a/packages/nuxt/src/runtime/modules/ses/index.ts b/packages/nuxt/src/runtime/modules/ses/index.ts index 365a6f07..42221313 100644 --- a/packages/nuxt/src/runtime/modules/ses/index.ts +++ b/packages/nuxt/src/runtime/modules/ses/index.ts @@ -10,13 +10,13 @@ export default definePergelModule({ dependencies: { '@aws-sdk/client-ses': '^3.470.0', }, + waitModule: ['nodeCron'], }, defaults: {}, - async setup({ nuxt }) { + async setup({ nuxt, moduleOptions }) { const resolver = createResolver(import.meta.url) - const module = nuxt._pergel._module - generateModuleRuntimeConfig(nuxt, { + generateModuleRuntimeConfig(nuxt, moduleOptions, { region: '', accessKeyId: '', secretAccessKey: '', @@ -24,8 +24,8 @@ export default definePergelModule({ addServerImportsDir(resolver.resolve('./composables')) nuxt._pergel.contents.push({ - moduleName: module.moduleName, - projectName: module.projectName, + moduleName: moduleOptions.moduleName, + projectName: moduleOptions.projectName, content: /* ts */` function ses() { return {