Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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()
}
40 changes: 40 additions & 0 deletions test/typescript-common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use script'

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