-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf(app-autoload): plugin-autoload support symlink
- Loading branch information
Showing
8 changed files
with
195 additions
and
24 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
packages/app-autoload/__tests__/fixtures/plugins/realPlugin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = async function (fastify, opts) { | ||
fastify.decorate('realPlugin', opts); | ||
}; | ||
|
||
module.exports.autoConfig = { | ||
realPlugin: 1, | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/app-autoload/__tests__/fixtures/plugins/simple/foo.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
module.exports = async function (fastify, opts) { | ||
fastify.decorate('foo', opts); | ||
}; | ||
|
||
module.exports.autoConfig = { | ||
foo: 1, | ||
}; |
7 changes: 7 additions & 0 deletions
7
packages/app-autoload/__tests__/fixtures/plugins/simple/test/index.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
exports.default = async function (fastify, opts) { | ||
fastify.decorate('test', opts); | ||
}; | ||
|
||
exports.autoConfig = { | ||
test: 1, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import fastify, {FastifyInstance} from 'fastify'; | ||
import path from 'path'; | ||
import {promises} from 'fs'; | ||
import pluginLoader from '../src/pluginLoader'; | ||
|
||
const {symlink, unlink} = promises; | ||
|
||
declare module 'fastify' { | ||
interface FastifyInstance { | ||
foo?: Record<string, unknown>; | ||
test?: Record<string, unknown>; | ||
realPlugin?: Record<string, unknown>; | ||
} | ||
}; | ||
|
||
|
||
describe('@hoth/app-autoload pluginLoader', () => { | ||
|
||
let fastifyInstance: FastifyInstance; | ||
|
||
beforeEach(() => { | ||
fastifyInstance = fastify({ | ||
logger: false, | ||
}); | ||
}); | ||
|
||
it('simple dir & file', async () => { | ||
await fastifyInstance.register(pluginLoader, { | ||
dir: path.join(__dirname, 'fixtures/plugins/simple'), | ||
options: { | ||
init: 1, | ||
} | ||
}); | ||
|
||
expect(fastifyInstance.foo).toEqual({ | ||
foo: 1, | ||
init: 1, | ||
}); | ||
|
||
expect(fastifyInstance.test).toEqual({ | ||
test: 1, | ||
init: 1, | ||
}); | ||
}); | ||
|
||
it('symlink file', async () => { | ||
await symlink( | ||
path.join(__dirname, 'fixtures/plugins/realPlugin.js'), | ||
path.join(__dirname, 'fixtures/plugins/empty/realPlugin.js') | ||
); | ||
|
||
await fastifyInstance.register(pluginLoader, { | ||
dir: path.join(__dirname, 'fixtures/plugins/empty'), | ||
options: { | ||
init: 1, | ||
} | ||
}); | ||
|
||
expect(fastifyInstance.realPlugin).toEqual({ | ||
realPlugin: 1, | ||
init: 1, | ||
}); | ||
await unlink(path.join(__dirname, 'fixtures/plugins/empty/realPlugin.js')); | ||
}); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import fp from 'fastify-plugin'; | ||
import {promises} from 'fs'; | ||
import path from 'path'; | ||
import type {FastifyInstance} from 'fastify'; | ||
import {pathToFileURL} from 'url'; | ||
|
||
const {readdir, realpath, stat} = promises; | ||
|
||
interface PluginLoaderOptions { | ||
dir: string; | ||
options?: Record<string, unknown>; | ||
dirNameRoutePrefix?: boolean; | ||
} | ||
|
||
interface PluginItem { | ||
file: string; | ||
} | ||
|
||
type PluginTree = Record<string, PluginItem[]>; | ||
|
||
const ingnoreRegexp = /\.(map|d\.ts)$/; | ||
|
||
async function findPlugins(dir: string, pluginTree: PluginTree = {}, prefix: string = '/', depth: number = 0) { | ||
const list = await readdir(dir, { | ||
withFileTypes: true | ||
}); | ||
|
||
pluginTree[prefix] = pluginTree[prefix] || []; | ||
|
||
for await (const dirent of list) { | ||
|
||
if (ingnoreRegexp.test(dirent.name)) { | ||
continue; | ||
} | ||
|
||
const atMaxDepth = 2 <= depth; | ||
const file = path.join(dir, dirent.name); | ||
|
||
if (dirent.isDirectory() && !atMaxDepth) { | ||
await findPlugins(file, pluginTree, `${prefix}${prefix.endsWith('/') ? '' : '/'}${dirent.name}`, depth + 1); | ||
} | ||
else if (dirent.isFile()) { | ||
pluginTree[prefix].push({ | ||
file, | ||
}); | ||
} | ||
else if (dirent.isSymbolicLink()) { | ||
const finalFile = await realpath(file); | ||
const fileStat = await stat(finalFile); | ||
|
||
if (fileStat.isFile()) { | ||
pluginTree[prefix].push({ | ||
file: finalFile, | ||
}); | ||
} | ||
} | ||
} | ||
|
||
return pluginTree; | ||
} | ||
|
||
function loadModule(file: string) { | ||
if (typeof require !== 'undefined') { | ||
/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports */ | ||
return require(file); | ||
} | ||
return import(pathToFileURL(file).toString()); | ||
} | ||
|
||
export default fp(async function pluginAutoLoad(fastify: FastifyInstance, opts: PluginLoaderOptions) { | ||
|
||
const pluginTree = await findPlugins(opts.dir); | ||
|
||
for await (const [prefix, pluginArray] of Object.entries(pluginTree)) { | ||
if (pluginArray.length <= 0) { | ||
continue; | ||
} | ||
|
||
for await (const {file} of pluginArray) { | ||
const content = await loadModule(file); | ||
const plugin = content.default || content; | ||
|
||
if (plugin.autoload === false || content.autoload === false) { | ||
continue; | ||
} | ||
|
||
const pluginConfig = (content.default && content.default.autoConfig) || content.autoConfig || {}; | ||
const pluginOptions = { | ||
...pluginConfig, | ||
...opts.options | ||
}; | ||
|
||
if (opts.dirNameRoutePrefix) { | ||
pluginOptions.prefix = prefix; | ||
} | ||
|
||
plugin[Symbol.for('skip-override')] = true; | ||
|
||
await fastify.register(plugin, pluginOptions); | ||
} | ||
} | ||
|
||
}, { | ||
name: '@hoth/app-plugin-autoload' | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters