I am trying to use google-cloud/secret-manager in the server side code for an Angular 19 SSR application. However, when I build or serve in dev, it throws the below error:
Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
➜ Local: http://localhost:4200/
➜ press h + enter to show help
11:19:30 AM [vite] (ssr) Error when evaluating SSR module ./server.mjs:
|- ReferenceError: __dirname is not defined
at node_modules/google-gax/build/src/grpc.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:38145:41)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/google-gax/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:54580:18)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/secret_manager_service_client.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:55012:24)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:56261:43)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:78769:14)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
ReferenceError: __dirname is not defined
at node_modules/google-gax/build/src/grpc.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:38145:41)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/google-gax/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:54580:18)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/secret_manager_service_client.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:55012:24)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:56261:43)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:78769:14)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
Going through the Angular 19 documentation, it mentions that third-party libraries can have CommonJS constructs. My project is, however, a fresh project.
Now on the google-cloud/secret-manager library, it uses google-gax and probably this package uses __dirname
construct in it.
Found similar issue from google-cloud-node repository, but not able to fit the solution into current Angular build system.
What I have tried till now is upgraded @google-cloud/secret-manager
to the latest available version (6.0.1
), which in case upgrades google-gax
(5.0.1-rc.0
) as well. Both provide TypeScript support as per NPM packages.
Steps to replicate:
- Ensure
node v18.x.x
is installed - Create a SSR application
npm install -g @angular/[email protected]
ng new --ssr
cd <project_directory>
npm i @google-cloud/secret-manager
- Modify the contents of the file
src/server.ts
:
import {
AngularNodeAppEngine,
createNodeRequestHandler,
isMainModule,
writeResponseToNodeResponse,
} from '@angular/ssr/node';
import express from 'express';
import { v1 } from '@google-cloud/secret-manager';
import { Application } from 'express';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const app = express();
const angularApp = new AngularNodeAppEngine();
const secretManagerClient = new v1.SecretManagerServiceClient();
async function fetchSecretByName(secretName: string): Promise<string | undefined> {
const [version] = await secretManagerClient.accessSecretVersion({ name: secretName });
const value = version.payload?.data?.toString();
return value;
}
function initializeSecretCreds(app: Application): void {
const secretPath = "projects/<gcp-project-id-number>/secrets/<secret-name>";
if (!secretPath) {
process.exit(1);
}
let value = null;
fetchSecretByName(`${secretPath}/versions/latest`)
.then(secret => {
value = secret;
if (!value) {
process.exit(1);
}
const secretValue = JSON.parse(value);
// do something with the secret value
})
.catch(err => {
process.exit(1);
})
}
app.use(
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
redirect: false,
}),
);
/**
* Handle all other requests by rendering the Angular application.
*/
app.use('/**', (req, res, next) => {
angularApp
.handle(req)
.then((response) =>
response ? writeResponseToNodeResponse(response, res) : next(),
)
.catch(next);
});
/**
* Start the server if this module is the main entry point.
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
*/
if (isMainModule(import.meta.url)) {
const port = process.env['PORT'] || 4000;
initializeSecretCreds(app);
app.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
/**
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
*/
export const reqHandler = createNodeRequestHandler(app);
Has anyone faced a similar issue with Angular 19 SSR and come up with a solution or any workaround for the same?
I am trying to use google-cloud/secret-manager in the server side code for an Angular 19 SSR application. However, when I build or serve in dev, it throws the below error:
Watch mode enabled. Watching for file changes...
NOTE: Raw file sizes do not reflect development server per-request transformations.
➜ Local: http://localhost:4200/
➜ press h + enter to show help
11:19:30 AM [vite] (ssr) Error when evaluating SSR module ./server.mjs:
|- ReferenceError: __dirname is not defined
at node_modules/google-gax/build/src/grpc.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:38145:41)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/google-gax/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:54580:18)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/secret_manager_service_client.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:55012:24)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:56261:43)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:78769:14)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
ReferenceError: __dirname is not defined
at node_modules/google-gax/build/src/grpc.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:38145:41)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/google-gax/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:54580:18)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/secret_manager_service_client.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:55012:24)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/v1/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:56261:43)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
at node_modules/@google-cloud/secret-manager/build/src/index.js (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\@google-cloud_secret-manager.js:78769:14)
at __require2 (C:\Users\user1\repositories\ssr-wbsite\.angular\cache\19.1.8\company-ssr-wbsite\vite\deps_ssr\chunk-GBTWTWDP.js:52:50)
Going through the Angular 19 documentation, it mentions that third-party libraries can have CommonJS constructs. My project is, however, a fresh project.
Now on the google-cloud/secret-manager library, it uses google-gax and probably this package uses __dirname
construct in it.
Found similar issue from google-cloud-node repository, but not able to fit the solution into current Angular build system.
What I have tried till now is upgraded @google-cloud/secret-manager
to the latest available version (6.0.1
), which in case upgrades google-gax
(5.0.1-rc.0
) as well. Both provide TypeScript support as per NPM packages.
Steps to replicate:
- Ensure
node v18.x.x
is installed - Create a SSR application
npm install -g @angular/[email protected]
ng new --ssr
cd <project_directory>
npm i @google-cloud/secret-manager
- Modify the contents of the file
src/server.ts
:
import {
AngularNodeAppEngine,
createNodeRequestHandler,
isMainModule,
writeResponseToNodeResponse,
} from '@angular/ssr/node';
import express from 'express';
import { v1 } from '@google-cloud/secret-manager';
import { Application } from 'express';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const app = express();
const angularApp = new AngularNodeAppEngine();
const secretManagerClient = new v1.SecretManagerServiceClient();
async function fetchSecretByName(secretName: string): Promise<string | undefined> {
const [version] = await secretManagerClient.accessSecretVersion({ name: secretName });
const value = version.payload?.data?.toString();
return value;
}
function initializeSecretCreds(app: Application): void {
const secretPath = "projects/<gcp-project-id-number>/secrets/<secret-name>";
if (!secretPath) {
process.exit(1);
}
let value = null;
fetchSecretByName(`${secretPath}/versions/latest`)
.then(secret => {
value = secret;
if (!value) {
process.exit(1);
}
const secretValue = JSON.parse(value);
// do something with the secret value
})
.catch(err => {
process.exit(1);
})
}
app.use(
express.static(browserDistFolder, {
maxAge: '1y',
index: false,
redirect: false,
}),
);
/**
* Handle all other requests by rendering the Angular application.
*/
app.use('/**', (req, res, next) => {
angularApp
.handle(req)
.then((response) =>
response ? writeResponseToNodeResponse(response, res) : next(),
)
.catch(next);
});
/**
* Start the server if this module is the main entry point.
* The server listens on the port defined by the `PORT` environment variable, or defaults to 4000.
*/
if (isMainModule(import.meta.url)) {
const port = process.env['PORT'] || 4000;
initializeSecretCreds(app);
app.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
/**
* Request handler used by the Angular CLI (for dev-server and during build) or Firebase Cloud Functions.
*/
export const reqHandler = createNodeRequestHandler(app);
Has anyone faced a similar issue with Angular 19 SSR and come up with a solution or any workaround for the same?
Share Improve this question asked Mar 31 at 9:03 adityaprakashadityaprakash 246 bronze badges1 Answer
Reset to default 0Given the third party library here, @google-cloud/secret-manager
might not support ESM as of now, probably found a way around to the __dirname
issue by making use of google-api-nodejs-client which is a wrapper over the Google REST APIs. Given this library has full typescript support, we can utilize the it to perform the same functionality of fetching secret value. The function mentioned above to fetch the secret value can be refactored in the given snippet:
...
// import { v1 } from '@google-cloud/secret-manager'; -- removed
import { google } from 'googleapis';
...
...
// const secretManagerClient = new v1.SecretManagerServiceClient(); -- removed
async function fetchSecretByName(secretName: string): Promise<string | undefined> { // refactored
const auth = new google.auth.GoogleAuth();
// obtain the current project Id
const project = await auth.getProjectId();
// build secret manager client
const secretManager = google.secretmanager({ auth: auth, version: 'v1' });
// fetch the secret value
const res = await secretManager.projects.secrets.versions.access({
name: secretName,
})
return Buffer.from(res.data.payload?.data?.toString() as string, 'base64').toString('utf8');
}
This helped overcome the issue of google-gax
used in google-cloud-node library. Hope this comes in help to someone facing a similar issue of google-cloud-node
in Angular 19 SSR.