Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ provider, such as `ts-node`. Otherwise, widening the acceptance extension here w
```

## Override TypeScript detection using an environment variable
> This plugin uses [native type stripping](https://nodejs.org/docs/latest-v23.x/api/typescript.html#modules-typescript) with Node 23 and later.

It is possible to override the automatic detection of a TypeScript-capable runtime using the `FASTIFY_AUTOLOAD_TYPESCRIPT` environment variable. If set to a truthy value Autoload will load `.ts` files, expecting that node has a TypeScript-capable loader.

Expand Down
13 changes: 10 additions & 3 deletions lib/find-plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,16 @@ function accumulatePlugin ({ file, type, opts, pluginTree, prefix }) {
}

function handleTypeScriptSupport (file, language, isHook = false) {
if (language === 'typescript' && !runtime.supportTypeScript) {
throw new Error(`@fastify/autoload cannot import ${isHook ? 'hooks ' : ''}plugin at '${file}'. To fix this error compile TypeScript to JavaScript or use 'ts-node' to run your app.`)
}
if (
language === 'typescript' &&
/* c8 ignore start - This cannot be reached from Node 23 native type-stripping */
!runtime.supportTypeScript
) {
throw new Error(
`@fastify/autoload cannot import ${isHook ? 'hooks ' : ''}plugin at '${file}'. To fix this error compile TypeScript to JavaScript or use 'ts-node' to run your app.`
)
}
/* c8 ignore end */
}

function filterPath (path, filter) {
Expand Down
11 changes: 9 additions & 2 deletions lib/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,8 @@ Object.defineProperties(runtime, {
runtime.tsm ||
runtime.tsx ||
runtime.esbuild ||
runtime.tsimp
runtime.tsimp ||
runtime.nodeVersion >= 23
)
return cache.supportTypeScript
}
Expand All @@ -130,7 +131,13 @@ Object.defineProperties(runtime, {
)
return cache.forceESM
}
}
},
nodeVersion: {
get () {
cache.nodeVersion ??= Number(process.version.split('.')[0].slice(1))
return cache.nodeVersion
},
},
})

module.exports = runtime
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"scripts": {
"lint": "eslint",
"lint:fix": "eslint --fix",
"test": "npm run typescript && npm run typescript:jest && npm run typescript:swc-node-register && npm run typescript:tsm && npm run typescript:tsx && npm run typescript:vitest && npm run typescript:esbuild && npm run unit",
"test": "npm run typescript && npm run typescript:native && npm run typescript:jest && npm run typescript:swc-node-register && npm run typescript:tsm && npm run typescript:tsx && npm run typescript:vitest && npm run typescript:esbuild && npm run unit",
"typescript": "tsd",
"typescript:jest": "jest",
"typescript:esm": "node scripts/unit-typescript-esm.js",
Expand All @@ -17,6 +17,7 @@
"typescript:tsx": "node scripts/unit-typescript-tsx.js",
"typescript:tsimp": "node scripts/unit-typescript-tsimp.js",
"typescript:esbuild": "node scripts/unit-typescript-esbuild.js",
"typescript:native": "node scripts/unit-typescript-native-type-stripping.js",
"typescript:vitest": "vitest run",
"typescript:vitest:dev": "vitest",
"unit": "node scripts/unit.js",
Expand Down
30 changes: 30 additions & 0 deletions scripts/unit-typescript-native-type-stripping.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use strict'

const { exec } = require('node:child_process')
const runtime = require('../lib/runtime')

function common () {
const args = ['node', 'test/typescript-common/index.ts']
const child = exec(args.join(' '), {
shell: true,
})
child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.once('close', esm)
}

function esm () {
const args = ['node', 'test/typescript-esm/forceESM.ts']

const child = exec(args.join(' '), {
shell: true,
})

child.stdout.pipe(process.stdout)
child.stderr.pipe(process.stderr)
child.once('close', process.exit)
}

if (runtime.nodeVersion >= 23) {
common()
}
5 changes: 2 additions & 3 deletions scripts/unit-typescript-tsx.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
'use strict'

const { exec } = require('node:child_process')

const version = Number(process.version.split('.')[0].slice(1))
const runtime = require('../lib/runtime')

const args = [
'npx',
version >= 18 ? '--node-options=--import=tsx' : '',
runtime.nodeVersion >= 18 ? '--node-options=--import=tsx' : '',
'tsnd',
'test/typescript/basic.ts'
]
Expand Down
13 changes: 10 additions & 3 deletions test/commonjs/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@

const t = require('tap')
const fastify = require('fastify')
const runtime = require('../../lib/runtime')

const typeStrippingEnabled = runtime.nodeVersion >= 23

t.test('independent of module support', function (t) {
t.plan(8)
t.plan(typeStrippingEnabled ? 7 : 8)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be removed when #440 is merged.

const app = fastify()

app.register(require('./syntax-error/app'))
Expand All @@ -28,8 +31,12 @@ t.test('independent of module support', function (t) {
app3.register(require('./ts-error/app'))

app3.ready(function (err) {
t.type(err, Error)
t.match(err.message, /cannot import plugin.*typescript/i)
if (typeStrippingEnabled) {
t.error(err)
} else {
t.type(err, Error)
t.match(err.message, /cannot import plugin.*typescript/i)
}
})

const app4 = fastify()
Expand Down
7 changes: 6 additions & 1 deletion test/issues/369/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { test } = require('tap')
const Fastify = require('fastify')
const path = require('node:path')
const autoload = require('../../..')
const runtime = require('../../../lib/runtime')

test('Should throw an error when trying to load invalid hooks', async (t) => {
const app = Fastify()
Expand All @@ -22,7 +23,11 @@ test('Should throw an error when trying to import hooks plugin using index.ts if
autoHooks: true
})

await t.rejects(app.ready(), new Error(`@fastify/autoload cannot import hooks plugin at '${path.join(__dirname, 'invalid-index-type/index.ts')}'`))
if (runtime.nodeVersion >= 23) {
t.doesNotThrow(() => app.ready())
} else {
await t.rejects(app.ready(), new Error(`@fastify/autoload cannot import hooks plugin at '${path.join(__dirname, 'invalid-index-type/index.ts')}'`))
}
})

test('Should not accumulate plugin if doesn\'t comply to matchFilter', async (t) => {
Expand Down
12 changes: 12 additions & 0 deletions test/typescript-common/basic/app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import type { FastifyInstance } from 'fastify'

const { join } = require('node:path')
const fastifyAutoLoad = require('../../../index.js')

module.exports = function (fastify: FastifyInstance, _opts: any, next: any) {
fastify.register(fastifyAutoLoad, {
dir: join(__dirname, 'foo'),
})

next()
}
9 changes: 9 additions & 0 deletions test/typescript-common/basic/foo/javascript.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use strict'

module.exports = function (fastify, _opts, next) {
fastify.get('/javascript', (_request, reply) => {
reply.send({ script: 'java' })
})

next()
}
3 changes: 3 additions & 0 deletions test/typescript-common/basic/foo/shouldBeIgnored.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// See https://github.com/fastify/fastify-autoload/issues/65
declare const definitionFilesAreIncluded: never
export default definitionFilesAreIncluded
7 changes: 7 additions & 0 deletions test/typescript-common/basic/foo/typescript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = function (fastify: any, _opts, next) {
fastify.get('/typescript', (_request, reply) => {
reply.send({ script: 'type' })
})

next()
}
38 changes: 38 additions & 0 deletions test/typescript-common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const t = require('tap')
const fastify = require('fastify')

const basicApp = require('./basic/app.ts')
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extensions seems mandatory for ts file too.


t.plan(5)

const app = fastify()

app.register(basicApp)

app.ready(async function (err) {
t.error(err)

await app
.inject({
url: '/javascript',
})
.then(function (res: any) {
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.payload), { script: 'java' })
})
.catch((err) => {
t.error(err)
})

await app
.inject({
url: '/typescript',
})
.then(function (res: any) {
t.equal(res.statusCode, 200)
t.same(JSON.parse(res.payload), { script: 'type' })
})
.catch((err) => {
t.error(err)
})
})
2 changes: 1 addition & 1 deletion test/typescript-esm/app/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From API docs:

Due to the nature of type stripping, the type keyword is necessary to correctly strip type imports.


export default function (fastify: FastifyInstance, _: object, next: (err?: Error) => void): void {
fastify.get('/installed', (_: FastifyRequest, reply: FastifyReply): void => {
Expand Down
2 changes: 1 addition & 1 deletion test/typescript-esm/forceESM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fastify from 'fastify'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
import t from 'tap'
import fastifyAutoLoad from '../../'
import fastifyAutoLoad from '../../index.js'

t.plan(4)

Expand Down
Loading