diff --git a/package.json b/package.json index 98db65e1ad..de16de02e2 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "table": "^6.8.0", "ufo": "^0.7.9", "unenv": "^0.4.3", + "unimport": "0.0.8", "unstorage": "^0.3.3" }, "devDependencies": { diff --git a/src/build.ts b/src/build.ts index ca8eaec558..b314530dbe 100644 --- a/src/build.ts +++ b/src/build.ts @@ -96,6 +96,16 @@ export async function writeTypes (nitro: Nitro) { routeTypes[mw.route].push(`Awaited>`) } + let autoImportedTypes: string[] = [] + + if (nitro.unimport) { + autoImportedTypes = nitro.unimport + .generateTypeDecarations() + .trim() + .split('\n') + .slice(0, -1) // Remove the last `export {}` + } + const lines = [ '// Generated by nitro', 'declare module \'nitopack\' {', @@ -104,6 +114,7 @@ export async function writeTypes (nitro: Nitro) { ...Object.entries(routeTypes).map(([path, types]) => ` '${path}': ${types.join(' | ')}`), ' }', '}', + ...autoImportedTypes, // Makes this a module for augmentation purposes 'export {}' ] diff --git a/src/nitro.ts b/src/nitro.ts index b4734399cf..632c2e9985 100644 --- a/src/nitro.ts +++ b/src/nitro.ts @@ -1,5 +1,6 @@ import { resolve } from 'pathe' import { createHooks } from 'hookable' +import { createUnimport } from 'unimport' import type { NitroConfig, Nitro } from './types' import { resolvePath } from './utils' import { loadOptions } from './options' @@ -45,5 +46,9 @@ export async function createNitro (config: NitroConfig = {}): Promise { dir: resolve(nitro.options.srcDir, 'server/assets'), meta: true } + if (nitro.options.autoImport) { + nitro.unimport = createUnimport(nitro.options.autoImport) + } + return nitro } diff --git a/src/rollup/config.ts b/src/rollup/config.ts index bc21f46180..35472ebbed 100644 --- a/src/rollup/config.ts +++ b/src/rollup/config.ts @@ -16,6 +16,7 @@ import { visualizer } from 'rollup-plugin-visualizer' import * as unenv from 'unenv' import type { Preset } from 'unenv' import { sanitizeFilePath } from 'mlly' +import unimportPlugin from 'unimport/unplugin' import type { Nitro } from '../types' import { resolvePath } from '../utils' import { runtimeDir } from '../dirs' @@ -140,6 +141,10 @@ export const getRollupConfig = (nitro: Nitro) => { rollupConfig.plugins.push(timing()) } + if (nitro.options.autoImport) { + rollupConfig.plugins.push(unimportPlugin.rollup(nitro.options.autoImport)) + } + // Raw asset loader rollupConfig.plugins.push(raw()) diff --git a/src/server/dev.ts b/src/server/dev.ts index 11030d8c6c..a854700288 100644 --- a/src/server/dev.ts +++ b/src/server/dev.ts @@ -86,7 +86,7 @@ export function createDevServer (nitro: Nitro) { // debugging endpoint to view vfs app.use('/_vfs', useBase('/_vfs', handleVfs(nitro))) - // Dynamic Middlwware + // Dynamic Middleware const legacyMiddleware = createDynamicMiddleware() const devMiddleware = createDynamicMiddleware() app.use(legacyMiddleware.middleware) diff --git a/src/types/nitro.ts b/src/types/nitro.ts index 84ef5fe586..4d466bf360 100644 --- a/src/types/nitro.ts +++ b/src/types/nitro.ts @@ -1,5 +1,6 @@ /* eslint-disable no-use-before-define */ import type { Preset as UnenvPreset } from 'unenv' +import type { Unimport, UnimportOptions } from 'unimport' import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer' import type { NestedHooks, Hookable } from 'hookable' import type { NodeExternalsOptions } from '../rollup/plugins/externals' @@ -14,6 +15,7 @@ export interface Nitro { scannedMiddleware: NitroOptions['middleware'], vfs: Record hooks: Hookable + unimport?: Unimport } export interface NitroHooks { @@ -104,4 +106,6 @@ export interface NitroOptions { preview: string | ((nitro: Nitro) => string) deploy: string | ((nitro: Nitro) => string) } + + autoImport: UnimportOptions } diff --git a/test/fixture/api/kebab.ts b/test/fixture/api/kebab.ts new file mode 100644 index 0000000000..13f1a8a0f6 --- /dev/null +++ b/test/fixture/api/kebab.ts @@ -0,0 +1 @@ +export default () => kebabCase('HelloWorld') diff --git a/test/fixture/nitro.config.ts b/test/fixture/nitro.config.ts index 23e989eb02..cdc2dc14a4 100644 --- a/test/fixture/nitro.config.ts +++ b/test/fixture/nitro.config.ts @@ -1,3 +1,17 @@ import { defineNitroConfig } from '../..' -export default defineNitroConfig({}) +export default defineNitroConfig({ + autoImport: { + presets: [ + { + // TODO: move this to built-in preset + from: 'scule', + imports: [ + 'camelCase', + 'pascalCase', + 'kebabCase' + ] + } + ] + } +}) diff --git a/test/utils.ts b/test/utils.ts index 778dc86556..8b90f4cb8b 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -59,7 +59,9 @@ export function testNitro (_ctx, getHandler) { it('API Works', async () => { const { data: helloData } = await handler({ url: '/api/hello' }) const { data: heyData } = await handler({ url: '/api/hey' }) + const { data: kebabData } = await handler({ url: '/api/kebab' }) expect(destr(helloData)).to.have.string('Hello API') expect(destr(heyData)).to.have.string('Hey API') + expect(destr(kebabData)).to.have.string('hello-world') }) } diff --git a/yarn.lock b/yarn.lock index e6324a227a..03624683f9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2720,6 +2720,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^5.0.0": + version: 5.0.0 + resolution: "escape-string-regexp@npm:5.0.0" + checksum: 20daabe197f3cb198ec28546deebcf24b3dbb1a5a269184381b3116d12f0532e06007f4bc8da25669d6a7f8efb68db0758df4cd981f57bc5b57f521a3e12c59e + languageName: node + linkType: hard + "eslint-config-standard@npm:^16.0.3": version: 16.0.3 resolution: "eslint-config-standard@npm:16.0.3" @@ -4582,6 +4589,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.26.0": + version: 0.26.1 + resolution: "magic-string@npm:0.26.1" + dependencies: + sourcemap-codec: ^1.4.8 + checksum: 23f21f5734346ddfbabd7b9834e3ecda3521e3e1db81166c1513b45b729489bbed1eafa8cd052c7db7fdc7c68ebc5c03bc00dd5a23697edda15dbecaf8c98397 + languageName: node + linkType: hard + "make-dir@npm:^3.0.0, make-dir@npm:^3.1.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" @@ -4887,6 +4903,13 @@ __metadata: languageName: node linkType: hard +"mlly@npm:^0.4.3": + version: 0.4.3 + resolution: "mlly@npm:0.4.3" + checksum: d9d50babe73ab1157565e518dd38f7c4f0c3813ff36bb4eaff65ea51ea768f1ac76b0ae739edf261425dafe2efff11ef15546adbd94c2cd6e42beea8029a3aba + languageName: node + linkType: hard + "mri@npm:^1.1.6, mri@npm:^1.2.0": version: 1.2.0 resolution: "mri@npm:1.2.0" @@ -5038,6 +5061,7 @@ __metadata: ufo: ^0.7.9 unbuild: latest unenv: ^0.4.3 + unimport: 0.0.8 unstorage: ^0.3.3 vitest: ^0.3.2 vue: 3.2.29 @@ -6399,7 +6423,7 @@ __metadata: languageName: node linkType: hard -"sourcemap-codec@npm:^1.4.4": +"sourcemap-codec@npm:^1.4.4, sourcemap-codec@npm:^1.4.8": version: 1.4.8 resolution: "sourcemap-codec@npm:1.4.8" checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 @@ -6956,6 +6980,20 @@ unbuild@latest: languageName: node linkType: hard +"unimport@npm:0.0.8": + version: 0.0.8 + resolution: "unimport@npm:0.0.8" + dependencies: + "@rollup/pluginutils": ^4.1.2 + escape-string-regexp: ^5.0.0 + local-pkg: ^0.4.1 + magic-string: ^0.26.0 + mlly: ^0.4.3 + unplugin: ^0.3.3 + checksum: ac6e2ef860b274c28093117c23071aaa35f484f88ff23cd25a4f4d114c24e72969f46f729b26023546ffdc1016ef42e5fc399d14389c0c0374f4a74b17ff1955 + languageName: node + linkType: hard + "unique-filename@npm:^1.1.1": version: 1.1.1 resolution: "unique-filename@npm:1.1.1" @@ -6988,6 +7026,29 @@ unbuild@latest: languageName: node linkType: hard +"unplugin@npm:^0.3.3": + version: 0.3.3 + resolution: "unplugin@npm:0.3.3" + dependencies: + webpack-virtual-modules: ^0.4.3 + peerDependencies: + esbuild: ">=0.13" + rollup: ^2.50.0 + vite: ^2.3.0 + webpack: 4 || 5 + peerDependenciesMeta: + esbuild: + optional: true + rollup: + optional: true + vite: + optional: true + webpack: + optional: true + checksum: 11361432eed70ebd61da313d68f85b8c582738560a41cbfcb7c52e99c0654c9bcf83abb7db2bce74cbda63f8c691501cafb4208f04f0ef2542eee254c93cd3c5 + languageName: node + linkType: hard + "unstorage@npm:^0.3.3": version: 0.3.3 resolution: "unstorage@npm:0.3.3" @@ -7207,6 +7268,13 @@ unbuild@latest: languageName: node linkType: hard +"webpack-virtual-modules@npm:^0.4.3": + version: 0.4.3 + resolution: "webpack-virtual-modules@npm:0.4.3" + checksum: 158d30633e0d9be3cfcde10fe959b28df5d5adb1068e0f057fcfb10b0b16ede6c892eba438f6ced089c7c442087748c2fcd1e3f035e4e2dc6760517a8c227714 + languageName: node + linkType: hard + "whatwg-url@npm:^5.0.0": version: 5.0.0 resolution: "whatwg-url@npm:5.0.0"