Skip to content
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

cant use with swagger #406

Open
yeli19950109 opened this issue May 23, 2019 · 11 comments
Open

cant use with swagger #406

yeli19950109 opened this issue May 23, 2019 · 11 comments

Comments

@yeli19950109
Copy link

yeli19950109 commented May 23, 2019

cant use with swagger for nestjs

@styfle
Copy link
Member

styfle commented May 24, 2019

Hello @yeli19950109

Can you create an example that fails with ncc build?

@dominique-mueller
Copy link

dominique-mueller commented Jul 23, 2019

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 ...

@dominique-mueller
Copy link

dominique-mueller commented Jul 23, 2019

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: scottie1984/swagger-ui-express#114.

@mohammadzainabbas
Copy link

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 ??

@dominique-mueller
Copy link

dominique-mueller commented Apr 1, 2020

@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!

@eMarek
Copy link

eMarek commented Aug 6, 2020

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.

@tmtron
Copy link

tmtron commented Mar 11, 2021

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

"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-level node_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

  1. copy the relevant files to a folder which will be accessible (by node) at runtime, when we start the ncc output
  2. 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:
image

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

@Onihani
Copy link

Onihani commented Dec 6, 2022

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

@ramazansancar
Copy link

This is how I solved the problem.
Deploying Platform: Vercel

image

@kangfenmao
Copy link

I wrote a patch to solve this problem. use https://unpkg.com/swagger-ui-dist@5.6.2/ 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/swagger-ui-dist@5.6.2/')
         .replace('<% customJs %>', toTags(customJs, toExternalScriptTag))
         .replace('<% customJsStr %>', toTags(customJsStr, toInlineScriptTag))
         .replace('<% customCssUrl %>', toTags(customCssUrl, toExternalStylesheetTag))

Patch file

@nestjs+swagger+7.1.10.patch

@gaffarmalik
Copy link

gaffarmalik commented Sep 10, 2024

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests