-
Notifications
You must be signed in to change notification settings - Fork 504
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Live reloading with tsx
and tsoa
#1667
Comments
Hello there edwinhern 👋 Thank you for opening your very first issue in this project. We will try to get back to you as soon as we can.👀 |
I had a similar issue and this was my solution: Switch to the programatic generation rather than CLI commands: /**
* @name tsoa-generator.ts
* This file uses TSOA to generate the OpenAPI/Swagger spec, as well as the TSOA routes from the class controllers.
*/
import fs from "fs"
import path from "path"
import * as ts from "typescript"
import type {
ExtendedRoutesConfig,
ExtendedSpecConfig,
Config
} from "tsoa"
import {
generateRoutes,
generateSpec
} from "tsoa"
const dirname = import.meta.dirname
const appRoot = fs.existsSync( path.resolve( dirname, "tsoa.json" ) ) ? dirname : path.resolve( dirname, "../../../" )
// https://github.com/lukeautry/tsoa/issues/868#issuecomment-1445941911
// This probably isn't necessary in this applications case, but may save some trouble in the future
const tsConfigFileName = path.resolve( appRoot, "tsconfig.json" )
const tsConfigFile = ts.readConfigFile( tsConfigFileName, ( path, encoding?: string ) => ts.sys.readFile( path, encoding ) )
const tsConfigContent = ts.parseJsonConfigFileContent( tsConfigFile.config, ts.sys, dirname )
const tsCompilerOptions = tsConfigContent.options
// Import the config from `tsoa.json` - this makes it so options remain the same if we use the CLI or this function
const tsoaConfigFileName = path.resolve( appRoot, "tsoa.json" )
const tsoaConfigFileContent = fs.readFileSync( tsoaConfigFileName, "utf8" )
const tsoaConfig: Config = JSON.parse( tsoaConfigFileContent ) as Config
const specOptions = { ...tsoaConfig.spec, ...tsoaConfig } as ExtendedSpecConfig
const routeOptions = { ...tsoaConfig.routes, ...tsoaConfig } as ExtendedRoutesConfig
const generateTSOA = async (): Promise<void> => {
/**
* This function programatically generates the TSOA spec file and routes file.
* This is so the routes and spec can always be updated before launching the server.
*/
console.log( "Generating spec..." )
await generateSpec( specOptions, tsCompilerOptions, tsoaConfig.ignore )
console.log( "Generating routes..." )
await generateRoutes( routeOptions, tsCompilerOptions, tsoaConfig.ignore )
console.log( "Fixing routes imports..." )
const routesFile = path.resolve( tsoaConfig.routes.routesDir, "routes.ts" )
if ( tsCompilerOptions.verbatimModuleSyntax && fs.existsSync( routesFile ) ) {
const routesFileContents = fs.readFileSync( routesFile, "utf8" )
const lines = routesFileContents.split( "\n" )
lines.splice( 3, 0, "// @ts-ignore" )
fs.writeFileSync( routesFile, lines.join( "\n" ) )
}
console.log( "TSOA Generation complete." )
}
// Check if the current script is being run directly
const isRunDirectly = import.meta.url.includes( process.argv[ 1 ] ) && import.meta.url.includes( "tsoa-generator.ts" )
if ( isRunDirectly )
await generateTSOA()
export default generateTSOA Import the generator in my // ...
// Regenerate our routes before importing them
import generateTSOA from "./data/generators/tsoa-generator.ts"
await generateTSOA()
import { RegisterRoutes } from "./tsoa-build/routes.ts"
// ... Ignore the tsoa-build files in my "dev": "tsx watch --ignore 'src/tsoa-build/**' src/index.ts", Also can have a script if you want to run it seperately: "gen-tsoa": "tsx src/data/generators/tsoa-generator.ts", |
@blipk Awesome! I'll try it out tn :) |
Hey @blipk, it worked! I can now auto-generate with code changes. However, I'm stuck migrating from CommonJS to ESM. Do you have any advice? I pushed my latest code to this branch: GitHub Link. Since I had to use I'm using tsup for the build with this configuration: "tsup": {
"entry": ["src", "!src/**/__tests__/**", "!src/**/*.test.*"],
"sourcemap": false,
"clean": true,
"minify": true,
"format": ["esm"],
"skipNodeModulesBundle": true
} I've also tried to set the programmatic version to run only on development if (env.isDevelopment) await buildApiSpecAndRoutes(); Any tips or code reference would be greatly appreciated! |
I'm not sure as I'm not using tsup or esbuild. I just tried to build with Meaning I had to update my tsoa.json config to:
It builds fine now but not really usable as I only get types, but maybe it could help with your tsup problem I haven't set up a bundler yet and I'm probably just intending to run it directly with Let me know if you get it working and I might consider using tsup as well |
@edwinhern What error are you actually running into? I tried to build with tsup and it builds fine but when I run it I keep running into this:
I can resolve it by changing my import syntax to the commented format here: import { Get, Route, Tags, Post, Body, Path, Response, SuccessResponse, Controller, Res, TsoaResponse } from "tsoa"
// import * as tsoa from "tsoa"
// const { Get, Route, Tags, Post, Body, Path, Response, SuccessResponse, Controller, Res, TsoaResponse } = tsoa But I'd rather not do that. Do you have the same issue? |
After making the import changes I got it to run but had to change these two lines in //...
const appRoot = fs.existsSync( path.resolve( dirname, "tsoa.json" ) ) ? dirname : path.resolve( dirname, "../../../" )
//...
const isRunDirectly = import.meta.url.includes( process.argv[ 1 ] ) && import.meta.url.includes( "tsoa-generator.ts" )
//... As well as copying some files in my build script:
I also fixed my error by changing my imports to import the TsoaResponse as a type
I have lint rule for this, but I really should pay attention to the caveats: https://typescript-eslint.io/rules/consistent-type-imports/#caveat-decorators--experimentaldecorators-true--emitdecoratormetadata-true |
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days |
Sorting
I'm submitting a ...
I confirm that I
Expected Behavior
When I run
npm run debug
, it should enable hot/live reloading so that whenever I make changes to my code, the spec and routes files are automatically regenerated.Current Behavior
Currently, when I run
npm run debug
, the script"debug": "concurrently \"tsoa spec-and-routes\" \"npm:dev\"",
only executestsoa spec-and-routes
once on execution. It doesn't provide hot/live reloading functionality, which I need.Possible Solution
I'm looking for a solution that allows
tsoa
to watch my files and automatically regenerate the spec and routes files upon changes.Steps to Reproduce
https://github.com/edwinhern/express-typescript-2024.git
git checkout -b feat08.24-tsoa
npm ci
npm run debug
Context (Environment)
Version of the library: ^6.4.0
Version of NodeJS: 22.7.0
Detailed Description
I'm trying to run the following script:
However, instead of only running
tsoa spec-and-routes
on execution, I want to have hot/live reloading where any change in my TypeScript files will automatically regenerate the spec and routes files.Here’s my tsoa.json file:
I made the
outputDirectory
inside mysrc
folder so that when I build, it will compile the code rather than keeping it in thets
file forroutes.ts
.I'm currently working on the following branch: feat08.24-tsoa
Breaking change?
This is not a breaking change, but I want to ensure that the functionality doesn't disrupt the existing library operations. Any guidance on achieving this would be appreciated.
The text was updated successfully, but these errors were encountered: