Reputation: 216
I am trying to build Angular 17 application with SSR, using built in i18n mechanism. And I don't get how to configure it to work together. v17 is brand new and there are blank spaces in documentation and not a lot of examples over the Internet.
When creating simple application with Angular+SSR it creates server.ts
alongside base application
// imports
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
const server = express();
const serverDistFolder = dirname(fileURLToPath(import.meta.url));
const browserDistFolder = resolve(serverDistFolder, '../browser');
const indexHtml = join(serverDistFolder, 'index.server.html');
const commonEngine = new CommonEngine();
server.set('view engine', 'html');
server.set('views', browserDistFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(browserDistFolder, {
maxAge: '1y'
}));
// All regular routes use the Angular engine
server.get('*', (req, res, next) => {
const { protocol, originalUrl, baseUrl, headers } = req;
commonEngine
.render({
bootstrap,
documentFilePath: indexHtml,
url: `${protocol}://${headers.host}${originalUrl}`,
publicPath: browserDistFolder,
providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }],
})
.then((html) => res.send(html))
.catch((err) => next(err));
});
return server;
}
function run(): void {
const port = process.env['PORT'] || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
run();
and after building the app it creates the following structure in dist
folder:
# simple-ssr
* [browser/](./simple-ssr/browser)
* [first/](./simple-ssr/browser/first)
* [index.html](./simple-ssr/browser/first/index.html)
* [home/](./simple-ssr/browser/home)
* [index.html](./simple-ssr/browser/home/index.html)
* [second/](./simple-ssr/browser/second)
* [index.html](./simple-ssr/browser/second/index.html)
* [favicon.ico](./simple-ssr/browser/favicon.ico)
* [index.html](./simple-ssr/browser/index.html)
* [main-OUKHBY7S.js](./simple-ssr/browser/main-OUKHBY7S.js)
* [polyfills-LZBJRJJE.js](./simple-ssr/browser/polyfills-LZBJRJJE.js)
* [styles-Y4IFJ72L.css](./simple-ssr/browser/styles-Y4IFJ72L.css)
* [server/](./simple-ssr/server)
* [chunk-53JWIC36.mjs](./simple-ssr/server/chunk-53JWIC36.mjs)
* ... other chunks
* [index.server.html](./simple-ssr/server/index.server.html)
* [main.server.mjs](./simple-ssr/server/main.server.mjs)
* [polyfills.server.mjs](./simple-ssr/server/polyfills.server.mjs)
* [render-utils.server.mjs](./simple-ssr/server/render-utils.server.mjs)
* [server.mjs](./simple-ssr/server/server.mjs)
* [3rdpartylicenses.txt](./simple-ssr/3rdpartylicenses.txt)
* [prerendered-routes.json](./simple-ssr/prerendered-routes.json)
running node dist/simple-ssr/server/server.mjs
starts the Express server and everything works fine.
The problem starts after adding Angular built-in i18n.
Afer seetting up everything and localizing the app it works okay with ng serve
.
But building dist version it generates another nested structure:
# simple-ssr-with-i18n
* [browser/](./my-app/browser)
* [en-US/](./my-app/browser/en-US)
* [assets/](./my-app/browser/en-US/assets)
* [img/](./my-app/browser/en-US/assets/img)
* [first/](./my-app/browser/en-US/first)
* [index.html](./my-app/browser/en-US/first/index.html)
* [home/](./my-app/browser/en-US/home)
* [index.html](./my-app/browser/en-US/home/index.html)
* [second/](./my-app/browser/en-US/second)
* [index.html](./my-app/browser/en-US/second/index.html)
* [favicon.ico](./my-app/browser/en-US/favicon.ico)
* [index.html](./my-app/browser/en-US/index.html)
* [main-VKL3SVOT.js](./my-app/browser/en-US/main-VKL3SVOT.js)
* [polyfills-LQWQKVKW.js](./my-app/browser/en-US/polyfills-LQWQKVKW.js)
* [styles-UTKJIBJ7.css](./my-app/browser/en-US/styles-UTKJIBJ7.css)
* [uk/](./my-app/browser/uk)
* [assets/](./my-app/browser/uk/assets)
* [img/](./my-app/browser/uk/assets/img)
* [first/](./my-app/browser/uk/first)
* [index.html](./my-app/browser/uk/first/index.html)
* [home/](./my-app/browser/uk/home)
* [index.html](./my-app/browser/uk/home/index.html)
* [second/](./my-app/browser/uk/second)
* [index.html](./my-app/browser/uk/second/index.html)
* [favicon.ico](./my-app/browser/uk/favicon.ico)
* [index.html](./my-app/browser/uk/index.html)
* [main-VKL3SVOT.js](./my-app/browser/uk/main-VKL3SVOT.js)
* [polyfills-LQWQKVKW.js](./my-app/browser/uk/polyfills-LQWQKVKW.js)
* [styles-UTKJIBJ7.css](./my-app/browser/uk/styles-UTKJIBJ7.css)
* [server/](./my-app/server)
* [en-US/](./my-app/server/en-US)
* [index.server.html](./my-app/server/en-US/index.server.html)
* [main.server.mjs](./my-app/server/en-US/main.server.mjs)
* [polyfills.server.mjs](./my-app/server/en-US/polyfills.server.mjs)
* [render-utils.server.mjs](./my-app/server/en-US/render-utils.server.mjs)
* [server.mjs](./my-app/server/en-US/server.mjs)
* [uk/](./my-app/server/uk)
* [index.server.html](./my-app/server/uk/index.server.html)
* [main.server.mjs](./my-app/server/uk/main.server.mjs)
* [polyfills.server.mjs](./my-app/server/uk/polyfills.server.mjs)
* [render-utils.server.mjs](./my-app/server/uk/render-utils.server.mjs)
* [server.mjs](./my-app/server/uk/server.mjs)
* [3rdpartylicenses.txt](./my-app/3rdpartylicenses.txt)
* [prerendered-routes.json](./my-app/prerendered-routes.json)
folder structure for i18n & ssr
Obviously pathes in server.ts
and, as a result, in dist/simple-ssr-with-i18n/server/en-US/server.mjs
are not set up right for working correctly with different locale versions.
And as I imagined it should work simply with following changes
const languageFolder = basename(serverDistFolder);
const languagePath = `/${languageFolder}/`;
const browserDistFolder = resolve(
serverDistFolder,
'../../browser' + languagePath
);
and running separate express server instance for each locale. (Ideally one server serving all locales, of course)
But all of my attempts were not successful, running node dist/simple-ssr/server/server.mjs
leads to unresponsive site with errors fetching static .js file chunks.
May somebody provide some comprehensive example for server.ts
and setting up i18n+ssr together?
Only relible article I found is Angular-universal-and-i18n-working-together but it's outdated, and i get built-time errors on baseHref step. P.S. Chatgpt is aware of Angular 15 and Universal, so it's not also very helpfull.
Upvotes: 7
Views: 2681
Reputation: 216
Found another blog post about the topic Building multi-language applications with Server Side Rendering in Angular 17
Contacted the developers, and they kindly provided example for Ssr I18n Angular17.
Everything works like a charm. Highly appreciate it.
Upvotes: 10