ncc
ncc copied to clipboard
cant use with swagger
cant use with swagger for nestjs
Hello @yeli19950109
Can you create an example that fails with ncc build
?
I'm experiencing the same issue, the path to the Swagger UI assets is no longer correct after building the app with ncc
.
After some playing around, however, I've seem to found a workaround: Serving the static
folder manually, after the Swagger setup. Here's a code snippet, I'm using /swagger
as the public URL:
// ...
SwaggerModule.setup('/swagger', app, document);
app.useStaticAssets(join(__dirname, '/static'), {
prefix: '/swagger',
});
// ...
Plus, I had to install fastify-swagger
although I'm just using express
in NestJS ... just wtf?
This all works for now, but surely is not a very pretty solution ...
The real issue is probably how swagger-ui itself gets built and served, and not necessarily how ncc
tries to bundle it up. Related issue: https://github.com/scottie1984/swagger-ui-express/issues/114.
Any updates on this one ??
p.s: @dominique-mueller I have tried your proposed solution and it seems that I might be missing something out. Could you be kind enough to help me out with this issue ??
@mohammadzainabbas Sure, I took the time to prepare a repository here: https://github.com/dominique-mueller/ncc-nestjs-swagger-experiment. It's a working example, so you can clone it and play around with it. I also wrote a quick explanation in the README about what has to be done to get Swagger working in an existing ncc-NestJS project. Hope it helps!
I have issues with swagger-ui-express
as well after using ncc
. @dominique-mueller, thank you for your example. I am wondering if it would be possible to achieve similar fix with express
only? I am not using nestjs
in my project.
So my understanding of the issue is that swagger-ui works like this:
When a browser requests the swagger documentation URL (e.g. https://example.com/swagger/
):
- the swagger-ui module builds a dynamic html file and returns it to the client
- this contains relative links to some files: e.g.
swagger-ui-bundle.js
,swagger-ui.css
etc. - so these files must be accessible from the client browser
- this contains relative links to some files: e.g.
"normal" build (i.e. without ncc)
installed packages
- in the root of our project we have all dependencies in
node_modules
available - according to the NestJs Swagger Docs we install the npm packages:
-
@nestjs/swagger
-
swagger-ui-express
-
dependencies
- We use the NestJs
SwaggerModule
in our code, which will require('swagger-ui-express'), which in turn has a dependency on: -
swagger-ui-dist which is a small package that contains the assets
that swagger-ui needs at runtime: e.g.
swagger-ui-bundle.js
,swagger-ui.css
etc.
Runtime
When the server is running and the browser visits the swagger URL (e.g. https://example.com/swagger/
):
- express will handle the request
- the GET request for this path has been registered by the NestJs SwaggerModule
- and this returns the dynamic HTML page created by swagger-ui-express
- this HTML contains relative links:
so the browser will send new requests to get these files e.g.
https://example.com/swagger/swagger-ui-bundle.js
- these requests are also handled by express and the routes have been registered by swagger-ui-express , which just forwards the GET requests to the swagger-ui-dist package
- this works, because the package is required and NodeJs will resolve it according to its algorithm which in this case will find the
swagger-ui-dist
package in the top-levelnode_modules
folder
"ncc" build:
installed packages
None: in this case we don't have access to node_modules/swagger-ui-dist
i.e. the reason to use ncc is that we don't need the large node_modules
folder.
Runtime
So when we don't do anything special the swagger-html page will not work, because the requests for the
relative links in the dynamic HTML cannot be resolved (express will return a HTTP 404 - Not Found
error)
Fix
To fix this we must somehow provide these files. This requires 2 steps
- copy the relevant files to a folder which will be accessible (by node) at runtime, when we start the ncc output
- tell express to send those files to the client-browser when the correct URL is requested
copy files
This depends on your build tools: e.g. we use angular-cli, thus we can simply use assets to copy the relevant files, e.g.
"assets": [
{
"glob": "**/*.{js,css,html,png}",
"input": "./node_modules/swagger-ui-dist/",
"output": "./dist/assets/swagger-ui-dist/"
},
....
]
Where dist
is the ncc output dir (i.e. where the index.js
or main.js
file will be created)
serve files
When we use NestJs we can use this:
app.useStaticAssets(path.join(__dirname, 'assets/swagger-ui-dist/'), {
prefix: '/swagger'
});
where app
is our NestExpressApplication
.
So basically this just configures express to return the files in the assets/swagger-ui-dist/
folder when the URL starts with /swagger
: e.g. https://example.com/swagger/swagger-ui-bundle.js
Why installing "fastify-swagger" seems to work
This refers to the explanation in the ncc-nestjs-swagger-setup test project
I guess the reason is this:
When ncc analyses our code, it finds require('fastify-swagger')
in the SwaggerModule.
When the package is installed (i.e. exists in node_modules
), ncc will process it.
When the webpack-asset-relocator-loader
(used by ncc) will notice that the file prepare-swagger-ui.js needs the files in the static folder:
And thus it will copy these files to the static
folder in our dist
dir.
Now we could serve these files and the swagger URL may work.
I think this may not work reliably, because there is no guarantee that the swagger-ui-dist
version which is copied from the fastify-swagger
package is compatible to the version used by swagger-ui
.
So I think it's better to
- not include
fastify-swagger
- and instead copy the files from
/node_modules/swagger-ui-dist
- which exists it is listed as a dependency of swagger-ui-express
I was experiencing the same issue. Fortunately I got it to work without ncc. My solution is a bit hacky. Check out my solution on stack overflow: https://stackoverflow.com/a/74708365/13701992
This is how I solved the problem. Deploying Platform: Vercel
I wrote a patch to solve this problem. use https://unpkg.com/[email protected]/ as publicUrl
diff --git a/node_modules/@nestjs/swagger/dist/swagger-ui/constants.js b/node_modules/@nestjs/swagger/dist/swagger-ui/constants.js
index 6f47648..8776139 100644
--- a/node_modules/@nestjs/swagger/dist/swagger-ui/constants.js
+++ b/node_modules/@nestjs/swagger/dist/swagger-ui/constants.js
@@ -1,8 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.jsTemplateString = exports.htmlTemplateString = exports.favIconHtml = void 0;
-exports.favIconHtml = '<link rel="icon" type="image/png" href="<% baseUrl %>favicon-32x32.png" sizes="32x32" />' +
- '<link rel="icon" type="image/png" href="<% baseUrl %>favicon-16x16.png" sizes="16x16" />';
+exports.favIconHtml = '<link rel="icon" type="image/png" href="<% publicUrl %>favicon-32x32.png" sizes="32x32" />' +
+ '<link rel="icon" type="image/png" href="<% publicUrl %>favicon-16x16.png" sizes="16x16" />';
exports.htmlTemplateString = `
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
@@ -10,7 +10,7 @@ exports.htmlTemplateString = `
<head>
<meta charset="UTF-8">
<title><% title %></title>
- <link rel="stylesheet" type="text/css" href="<% baseUrl %>swagger-ui.css" >
+ <link rel="stylesheet" type="text/css" href="<% publicUrl %>swagger-ui.css" >
<% favIconString %>
<style>
html
@@ -71,8 +71,8 @@ exports.htmlTemplateString = `
<div id="swagger-ui"></div>
-<script src="<% baseUrl %>swagger-ui-bundle.js"> </script>
-<script src="<% baseUrl %>swagger-ui-standalone-preset.js"> </script>
+<script src="<% publicUrl %>swagger-ui-bundle.js"> </script>
+<script src="<% publicUrl %>swagger-ui-standalone-preset.js"> </script>
<script src="<% baseUrl %>swagger-ui-init.js"> </script>
<% customJs %>
<% customJsStr %>
diff --git a/node_modules/@nestjs/swagger/dist/swagger-ui/swagger-ui.js b/node_modules/@nestjs/swagger/dist/swagger-ui/swagger-ui.js
index c067725..d60f616 100644
--- a/node_modules/@nestjs/swagger/dist/swagger-ui/swagger-ui.js
+++ b/node_modules/@nestjs/swagger/dist/swagger-ui/swagger-ui.js
@@ -55,6 +55,7 @@ function buildSwaggerHTML(baseUrl, swaggerDoc, customOptions = {}) {
.replace('<% explorerCss %>', explorerCss)
.replace('<% favIconString %>', favIconString)
.replace(/<% baseUrl %>/g, baseUrl)
+ .replace(/<% publicUrl %>/g, 'https://unpkg.com/[email protected]/')
.replace('<% customJs %>', toTags(customJs, toExternalScriptTag))
.replace('<% customJsStr %>', toTags(customJsStr, toInlineScriptTag))
.replace('<% customCssUrl %>', toTags(customCssUrl, toExternalStylesheetTag))
Patch file
My swagger UI now shows with the correct CSS/JS after relocating it. But it still shows up as with the example "Petstore". Is there some kind of document (json) that's missing?