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

Transform/Manipulate index html before sending it #926

Open
1 task done
Kuirak opened this issue Jul 13, 2022 · 6 comments
Open
1 task done

Transform/Manipulate index html before sending it #926

Kuirak opened this issue Jul 13, 2022 · 6 comments

Comments

@Kuirak
Copy link

Kuirak commented Jul 13, 2022

Is there an existing issue that is already proposing this?

  • I have searched the existing issues

Is your feature request related to a problem? Please describe it

Expose a function to transform the index.html before sending it to the client to inject some variables or replace certain parts, without setting up a complete view engine setup.

Describe the solution you'd like

It would be great to expose a function transformIndexHtml?: (indexHtml: string)=> string | Promise<string>
With this function any transform can be handled.
Here is the diff file I use to patch-package this feature in our code base:

diff --git a/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts b/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
index a996aff..e1dd974 100644
--- a/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
+++ b/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
@@ -5,6 +5,7 @@ export interface ServeStaticModuleOptions {
     renderPath?: string | RegExp;
     serveRoot?: string;
     exclude?: string[];
+    transformIndexHtml?: (indexHtml: string) => string;
     serveStaticOptions?: {
         cacheControl?: boolean;
         dotfiles?: string;
diff --git a/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js b/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
index 75c9f9b..d447522 100644
--- a/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
+++ b/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
@@ -29,7 +29,19 @@ let ExpressLoader = class ExpressLoader extends abstract_loader_1.AbstractLoader
                         const stat = fs.statSync(indexFilePath);
                         options.serveStaticOptions.setHeaders(res, indexFilePath, stat);
                     }
-                    res.sendFile(indexFilePath);
+                    if(options.transformIndexHtml != null) {
+                      fs.readFile(indexFilePath, 'utf8', (err, data) => {
+                        if (err) {
+                            next(err);
+                            return;
+                        }
+                        const transformed = options.transformIndexHtml(data);
+                        res.set('Content-Type', 'text/html');
+                        res.send(transformed);
+                      })
+                    } else {
+                     res.sendFile(indexFilePath);
+                    }
                 }
                 else {
                     next();

Teachability, documentation, adoption, migration strategy

No response

What is the motivation / use case for changing the behavior?

We want to inject a variables into the index.html before sending it to the client. In our case we want to replace the <base href="/"/> with the correct baseUrl in case the application runs on a pathname e.g. http://localhost:3001/app. Additionally we want to set a variable on the window object. We don't want to setup the whole view engine and install something like ejs to do these simple transformations.

@didaquis
Copy link

I'm on the same position.

@Kuirak do you found a solution?

@Kuirak
Copy link
Author

Kuirak commented Jul 19, 2023

I'm on the same position.

@Kuirak do you found a solution?

@didaquis We are currently using the patch above via patch-package and do some simple string replace in the resulting html

@dtslvr
Copy link

dtslvr commented Aug 6, 2023

I have successfully set up your patch @Kuirak with serve-static 4.0.0 and configured ServeStaticModule like this:

ServeStaticModule.forRoot({
  rootPath: join(__dirname, '..', 'client', 'en'),
  serveRoot: '/en',
  transformIndexHtml: (indexHtml: string) => {
    console.log(indexHtml);
    return indexHtml;
  }
})

ExpressLoader is registered, but renderFn (and transformIndexHtml) is never called. Any idea why?

@alan-rotenberg
Copy link

I'm in the same boat, @dtslvr . Were you able to get it running?

@alan-rotenberg
Copy link

alan-rotenberg commented Aug 15, 2023

I tinkered with it a bit - it doesn't work because renderFn isn't called after you call espress.static()

This isn't what you'd check into the repo, but this got me past the issue --

diff --git a/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts b/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
index a996aff..e1dd974 100644
--- a/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
+++ b/node_modules/@nestjs/serve-static/dist/interfaces/serve-static-options.interface.d.ts
@@ -5,6 +5,7 @@ export interface ServeStaticModuleOptions {
     renderPath?: string | RegExp;
     serveRoot?: string;
     exclude?: string[];
+    transformIndexHtml?: (indexHtml: string) => string;
     serveStaticOptions?: {
         cacheControl?: boolean;
         dotfiles?: string;
diff --git a/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js b/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
index 75c9f9b..2411238 100644
--- a/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
+++ b/node_modules/@nestjs/serve-static/dist/loaders/express.loader.js
@@ -43,6 +43,23 @@ let ExpressLoader = class ExpressLoader extends abstract_loader_1.AbstractLoader
                 app.get(renderPath, renderFn);
             }
             else {
+                app.use((req, res, next) => {
+                    if('/' == req.originalUrl && options.transformIndexHtml != null) {
+                        fs.readFile(indexFilePath, 'utf8', (err, data) => {
+                        if (err) {
+                            next(err);
+                            return;
+                        }
+                        const transformed = options.transformIndexHtml(data);
+                        res.set('Content-Type', 'text/html');
+                        res.send(transformed);
+                        })
+                    }
+                    else{
+                        next();
+                    };
+                });
+
                 app.use(express.static(clientPath, options.serveStaticOptions));
                 app.get(options.renderPath, renderFn);
             }

@dtslvr
Copy link

dtslvr commented Aug 15, 2023

I'm in the same boat, @dtslvr . Were you able to get it running?

No, but I'm going with a solution @geongeorge has suggested using an express middleware. Something like this:

// main.ts

app.use(StaticMiddleware);

and

// static.middleware.ts

export const StaticMiddleware = async (
  request: Request,
  response: Response,
  next: NextFunction
) => {
  if (...) {
    response.send(transformedIndexHtml);
  } else {
    next();
  } 
}

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

No branches or pull requests

4 participants