fastify / fastify-autoload

Require all plugins in a directory
MIT License
333 stars 67 forks source link

Dependency of plugin not registered when the plugins folder has subfolders structure #414

Closed mauro-d closed 1 month ago

mauro-d commented 1 month ago

Prerequisites

Fastify version

5.0.0

Plugin version

6.0.1

Node.js version

22.x

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

15.0

Description

I've a project structure like the following:

.
├── index.mjs
├── package.json
└── plugins
    ├── plugin-a
    │   └── index.mjs
    └── plugin-b
        └── index.mjs

Starting the server produces this error: The dependency 'plugin-b' of plugin 'plugin-a' is not registered. It does not happen if the plugins folder structure is like the following:

└── plugins
    ├── plugin-a.mjs
    └── plugin-b.mjs

To reproduce

package.json

{
  "dependencies": {
    "@fastify/autoload": "^6.0.1",
    "fastify": "^5.0.0",
    "fastify-plugin": "^5.0.1"
  }
}

index.mjs

import autoload from '@fastify/autoload'
import Fastify from 'fastify'
import path, { dirname } from 'path'
import { fileURLToPath } from 'url'

const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)

const fastify = Fastify({
  logger: true
})

fastify.register(autoload, {
  dir: path.join(__dirname, 'plugins')
})

fastify.listen({ port: 3000 }, (err, address) => {
  if (err) throw err
})

plugins/plugin-a/index.mjs

import fp from 'fastify-plugin'

const name = 'plugin-a'

const plugin = (fastify, options, done) => {
  console.log(name)
  done()
}

export default fp(plugin, {
  name,
  dependencies: ['plugin-b']
})

plugins/plugin-b/index.mjs

import fp from 'fastify-plugin'

const name = 'plugin-b'

const plugin = (fastify, options, done) => {
  console.log(name)
  done()
}

export default fp(plugin, {
  name
})

type node index.mjs.

Possible solution

I've modified the the function loadPlugins in the index.js file of the autoload module in the following way and it seems to work again:

async function loadPlugins ({ pluginTree, options, opts, fastify }) {
  const pluginsMeta = {}
  const hooksMeta = {}
  for (const key in pluginTree) {
    const { plugins, hooks } = pluginTree[key]
    await Promise.all(plugins.map(({ file, type, prefix }) => {
      return loadPlugin({ file, type, directoryPrefix: prefix, options: opts, log: fastify.log })
        .then((plugin) => {
          if (plugin) {
            // create route parameters from prefixed folders
            if (options.routeParams && plugin.options.prefix) {
              plugin.options.prefix = replaceRouteParamPattern(plugin.options.prefix)
            }
            pluginsMeta[plugin.name] = plugin
          }
        })
        .catch((err) => {
          throw enrichError(err)
        })
    }))
    await Promise.all(hooks.map((h) => {
      return loadHook(h, opts)
        .then((hookPlugin) => {
          hooksMeta[h.file] = hookPlugin
        })
        .catch((err) => {
          throw enrichError(err)
        })
    }))
  }

  const node = {
    pluginsMeta,
    hooksMeta
  }
  for (const key in pluginTree) {
    node.plugins = pluginTree[key].plugins
    node.hooks = pluginTree[key].hooks
    registerNode(node, fastify)
  }
}

Link to code that reproduces the bug

No response

Expected Behavior

plugin-b should be loaded before plugin-a and should be produced the following log:

plugin-b
plugin-a
jean-michelet commented 1 month ago

Hi, is it solved by #415?

mauro-d commented 1 month ago

Hi, yes, now it seems to be working again, thank you.