diff --git a/package.json b/package.json index 67afdbd08d50..ccc580918e67 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "@types/babel__core": "7.20.5", "@types/babel__generator": "^7.6.8", "@types/browser-sync": "^2.27.0", - "@types/express": "^4.16.0", + "@types/express": "~5.0.1", "@types/http-proxy": "^1.17.4", "@types/ini": "^4.0.0", "@types/jasmine": "~5.1.0", @@ -106,7 +106,7 @@ "eslint-config-prettier": "10.1.1", "eslint-plugin-header": "3.1.1", "eslint-plugin-import": "2.31.0", - "express": "4.21.2", + "express": "5.1.0", "fast-glob": "3.3.3", "globals": "16.0.0", "http-proxy": "^1.18.1", diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts index 36808413c2c7..4f1db1d17b17 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/proxy_spec.ts @@ -39,11 +39,12 @@ describe('Serve SSR Builder', () => { server.set('view engine', 'html'); server.set('views', distFolder); - server.get('*.*', express.static(distFolder, { - maxAge: '1y' + server.use(express.static(distFolder, { + maxAge: '1y', + index: false, })); - server.get('*', (req, res, next) => { + server.use((req, res, next) => { commonEngine .render({ bootstrap: AppServerModule, diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts index 4a3725c100c4..6182b2e2baba 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/ssl_spec.ts @@ -39,11 +39,12 @@ describe('Serve SSR Builder', () => { server.set('view engine', 'html'); server.set('views', distFolder); - server.get('*.*', express.static(distFolder, { - maxAge: '1y' + server.use(express.static(distFolder, { + maxAge: '1y', + index: false, })); - server.get('*', (req, res, next) => { + server.use((req, res, next) => { commonEngine .render({ bootstrap: AppServerModule, diff --git a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts index 857e6ab8ea5b..5944eb31c09d 100644 --- a/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/ssr-dev-server/specs/works_spec.ts @@ -38,11 +38,12 @@ describe('Serve SSR Builder', () => { server.set('view engine', 'html'); server.set('views', distFolder); - server.get('*.*', express.static(distFolder, { - maxAge: '1y' + server.use(express.static(distFolder, { + maxAge: '1y', + index: false, })); - server.get('*', (req, res, next) => { + server.use((req, res, next) => { commonEngine .render({ bootstrap: AppServerModule, diff --git a/packages/schematics/angular/migrations/use-application-builder/migration.ts b/packages/schematics/angular/migrations/use-application-builder/migration.ts index 464f6b4bf560..4bcf6d9e6ee6 100644 --- a/packages/schematics/angular/migrations/use-application-builder/migration.ts +++ b/packages/schematics/angular/migrations/use-application-builder/migration.ts @@ -158,7 +158,6 @@ function* updateBuildTarget( yield externalSchematic('@schematics/angular', 'ssr', { project: projectName, - skipInstall: true, }); } } diff --git a/packages/schematics/angular/ssr/files/application-builder/server.ts.template b/packages/schematics/angular/ssr/files/application-builder/server.ts.template index adb6684f97b3..6fb8b2c77e5a 100644 --- a/packages/schematics/angular/ssr/files/application-builder/server.ts.template +++ b/packages/schematics/angular/ssr/files/application-builder/server.ts.template @@ -18,7 +18,7 @@ const angularApp = new AngularNodeAppEngine(); * * Example: * ```ts - * app.get('/api/**', (req, res) => { + * app.get('/api/{*splat}', (req, res) => { * // Handle API request * }); * ``` @@ -38,7 +38,7 @@ app.use( /** * Handle all other requests by rendering the Angular application. */ -app.use('/**', (req, res, next) => { +app.use((req, res, next) => { angularApp .handle(req) .then((response) => @@ -53,7 +53,11 @@ app.use('/**', (req, res, next) => { */ if (isMainModule(import.meta.url)) { const port = process.env['PORT'] || 4000; - app.listen(port, () => { + app.listen(port, (error) => { + if (error) { + throw error; + } + console.log(`Node Express server listening on http://localhost:${port}`); }); } diff --git a/packages/schematics/angular/ssr/files/server-builder/server.ts.template b/packages/schematics/angular/ssr/files/server-builder/server.ts.template index 1d985bd60030..7567fa65a81d 100644 --- a/packages/schematics/angular/ssr/files/server-builder/server.ts.template +++ b/packages/schematics/angular/ssr/files/server-builder/server.ts.template @@ -21,14 +21,15 @@ export function app(): express.Express { server.set('views', distFolder); // Example Express Rest API endpoints - // server.get('/api/**', (req, res) => { }); + // server.get('/api/{*splat}', (req, res) => { }); // Serve static files from /browser - server.get('*.*', express.static(distFolder, { - maxAge: '1y' + server.use(express.static(distFolder, { + maxAge: '1y', + index: false, })); // All regular routes use the Angular engine - server.get('*', (req, res, next) => { + server.use((req, res, next) => { const { protocol, originalUrl, baseUrl, headers } = req; commonEngine @@ -51,7 +52,11 @@ function run(): void { // Start up the Node server const server = app(); - server.listen(port, () => { + server.listen(port, (error) => { + if (error) { + throw error; + } + console.log(`Node Express server listening on http://localhost:${port}`); }); } diff --git a/packages/schematics/angular/ssr/index.ts b/packages/schematics/angular/ssr/index.ts index b6352428079f..b81188340f0b 100644 --- a/packages/schematics/angular/ssr/index.ts +++ b/packages/schematics/angular/ssr/index.ts @@ -24,6 +24,7 @@ import { posix } from 'node:path'; import { Schema as ServerOptions } from '../server/schema'; import { DependencyType, + ExistingBehavior, InstallBehavior, addDependency, readWorkspace, @@ -299,10 +300,12 @@ function addDependencies({ skipInstall }: SSROptions, isUsingApplicationBuilder: addDependency('express', latestVersions['express'], { type: DependencyType.Default, install, + existing: ExistingBehavior.Replace, }), addDependency('@types/express', latestVersions['@types/express'], { type: DependencyType.Dev, install, + existing: ExistingBehavior.Replace, }), ]; diff --git a/packages/schematics/angular/utility/latest-versions/package.json b/packages/schematics/angular/utility/latest-versions/package.json index 406f275d0d66..92b883e83855 100644 --- a/packages/schematics/angular/utility/latest-versions/package.json +++ b/packages/schematics/angular/utility/latest-versions/package.json @@ -3,11 +3,11 @@ "comment": "This file is needed so that dependencies are synced by Renovate.", "private": true, "dependencies": { - "@types/express": "^4.17.17", + "@types/express": "^5.0.1", "@types/jasmine": "~5.1.0", "@types/node": "^20.17.19", "browser-sync": "^3.0.0", - "express": "^4.18.2", + "express": "^5.1.0", "jasmine-core": "~5.6.0", "jasmine-spec-reporter": "~7.0.0", "karma-chrome-launcher": "~3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 553c6358c4b0..0d8263d0dd05 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,8 +96,8 @@ importers: specifier: ^2.27.0 version: 2.29.0 '@types/express': - specifier: ^4.16.0 - version: 4.17.21 + specifier: ~5.0.1 + version: 5.0.1 '@types/http-proxy': specifier: ^1.17.4 version: 1.17.16 @@ -195,8 +195,8 @@ importers: specifier: 2.31.0 version: 2.31.0(@typescript-eslint/parser@8.28.0(eslint@9.23.0(jiti@1.21.7))(typescript@5.8.2))(eslint@9.23.0(jiti@1.21.7)) express: - specifier: 4.21.2 - version: 4.21.2 + specifier: 5.1.0 + version: 5.1.0 fast-glob: specifier: 3.3.3 version: 3.3.3 @@ -2667,9 +2667,15 @@ packages: '@types/express-serve-static-core@4.19.6': resolution: {integrity: sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==} + '@types/express-serve-static-core@5.0.6': + resolution: {integrity: sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==} + '@types/express@4.17.21': resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/express@5.0.1': + resolution: {integrity: sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==} + '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -3124,6 +3130,10 @@ packages: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3464,6 +3474,10 @@ packages: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + bonjour-service@1.3.0: resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==} @@ -3756,6 +3770,10 @@ packages: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} @@ -3769,6 +3787,10 @@ packages: cookie-signature@1.0.6: resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + cookie@0.7.1: resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} engines: {node: '>= 0.6'} @@ -4410,6 +4432,10 @@ packages: resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} engines: {node: '>= 0.10.0'} + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -4494,6 +4520,10 @@ packages: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + find-cache-dir@3.3.2: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} @@ -4568,6 +4598,10 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -5141,6 +5175,9 @@ packages: is-promise@2.2.2: resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} @@ -5658,6 +5695,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + memfs@4.17.0: resolution: {integrity: sha512-4eirfZ7thblFmqFjywlTmuWVSvccHAJbn1r8qQLzmTO11qcqpohOjmY2mFce6x7x7WtskzRqApPD0hv+Oa74jg==} engines: {node: '>= 4.0.0'} @@ -5665,6 +5706,10 @@ packages: merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} @@ -5692,6 +5737,10 @@ packages: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -6281,6 +6330,10 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -6557,6 +6610,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} @@ -6726,6 +6783,10 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} @@ -6837,6 +6898,10 @@ packages: resolution: {integrity: sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==} engines: {node: '>= 0.8.0'} + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} @@ -6848,6 +6913,10 @@ packages: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + server-destroy@1.0.1: resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==} @@ -7368,6 +7437,10 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -9730,7 +9803,7 @@ snapshots: '@types/cookies@0.9.0': dependencies: '@types/connect': 3.4.38 - '@types/express': 4.17.21 + '@types/express': 5.0.1 '@types/keygrip': 1.0.6 '@types/node': 20.17.28 @@ -9765,6 +9838,13 @@ snapshots: '@types/range-parser': 1.2.7 '@types/send': 0.17.4 + '@types/express-serve-static-core@5.0.6': + dependencies: + '@types/node': 20.17.28 + '@types/qs': 6.9.18 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + '@types/express@4.17.21': dependencies: '@types/body-parser': 1.19.5 @@ -9772,6 +9852,12 @@ snapshots: '@types/qs': 6.9.18 '@types/serve-static': 1.15.7 + '@types/express@5.0.1': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.6 + '@types/serve-static': 1.15.7 + '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 @@ -9937,7 +10023,7 @@ snapshots: '@types/serve-index@1.9.4': dependencies: - '@types/express': 4.17.21 + '@types/express': 5.0.1 '@types/serve-static@1.15.7': dependencies: @@ -10512,6 +10598,11 @@ snapshots: mime-types: 2.1.35 negotiator: 0.6.3 + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + acorn-jsx@5.3.2(acorn@8.14.1): dependencies: acorn: 8.14.1 @@ -10844,6 +10935,20 @@ snapshots: transitivePeerDependencies: - supports-color + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0(supports-color@10.0.0) + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + bonjour-service@1.3.0: dependencies: fast-deep-equal: 3.1.3 @@ -11221,6 +11326,10 @@ snapshots: dependencies: safe-buffer: 5.2.1 + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + content-type@1.0.5: {} convert-source-map@1.9.0: {} @@ -11229,6 +11338,8 @@ snapshots: cookie-signature@1.0.6: {} + cookie-signature@1.2.2: {} + cookie@0.7.1: {} cookie@0.7.2: {} @@ -11987,6 +12098,38 @@ snapshots: transitivePeerDependencies: - supports-color + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0(supports-color@10.0.0) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + extend@3.0.2: {} external-editor@3.1.0: @@ -12094,6 +12237,17 @@ snapshots: transitivePeerDependencies: - supports-color + finalhandler@2.1.0: + dependencies: + debug: 4.4.0(supports-color@10.0.0) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 @@ -12169,6 +12323,8 @@ snapshots: fresh@0.5.2: {} + fresh@2.0.0: {} + fs-constants@1.0.0: {} fs-extra@3.0.1: @@ -12800,6 +12956,8 @@ snapshots: is-promise@2.2.2: {} + is-promise@4.0.0: {} + is-reference@1.2.1: dependencies: '@types/estree': 1.0.7 @@ -13420,6 +13578,8 @@ snapshots: media-typer@0.3.0: {} + media-typer@1.1.0: {} + memfs@4.17.0: dependencies: '@jsonjoy.com/json-pack': 1.2.0(tslib@2.8.1) @@ -13429,6 +13589,8 @@ snapshots: merge-descriptors@1.0.3: {} + merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} merge2@1.4.1: {} @@ -13448,6 +13610,10 @@ snapshots: dependencies: mime-db: 1.52.0 + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + mime@1.6.0: {} mime@2.6.0: {} @@ -13991,6 +14157,8 @@ snapshots: path-to-regexp@0.1.12: {} + path-to-regexp@8.2.0: {} + path-type@4.0.0: {} pathe@1.1.2: {} @@ -14323,6 +14491,13 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -14556,6 +14731,16 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.38.0 fsevents: 2.3.3 + router@2.2.0: + dependencies: + debug: 4.4.0(supports-color@10.0.0) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + run-applescript@7.0.0: {} run-parallel@1.2.0: @@ -14683,6 +14868,22 @@ snapshots: transitivePeerDependencies: - supports-color + send@1.2.0: + dependencies: + debug: 4.4.0(supports-color@10.0.0) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 @@ -14708,6 +14909,15 @@ snapshots: transitivePeerDependencies: - supports-color + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + server-destroy@1.0.1: {} set-blocking@2.0.0: {} @@ -15335,6 +15545,12 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts index 383674369be1..19e7dcd28b60 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-csp-nonce.ts @@ -3,20 +3,13 @@ import { rimraf, writeMultipleFiles } from '../../../utils/fs'; import { findFreePort } from '../../../utils/network'; import { installWorkspacePackages } from '../../../utils/packages'; import { execAndWaitForOutputToMatch, ng } from '../../../utils/process'; -import { updateJsonFile, updateServerFileForWebpack, useSha } from '../../../utils/project'; +import { updateJsonFile, updateServerFileForEsbuild, useSha } from '../../../utils/project'; export default async function () { const useWebpackBuilder = !getGlobalVariable('argv')['esbuild']; // forcibly remove in case another test doesn't clean itself up await rimraf('node_modules/@angular/ssr'); - - if (useWebpackBuilder) { - // `--server-routing` not supported in `browser` builder. - await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); - } else { - await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); - } - + await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); await useSha(); await installWorkspacePackages(); @@ -27,7 +20,7 @@ export default async function () { build.configurations.production.prerender = false; }); - await updateServerFileForWebpack('src/server.ts'); + await updateServerFileForEsbuild('src/server.ts'); } await writeMultipleFiles({ diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts index 8313496d2046..a2b1c6a6cc34 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-ngmodule.ts @@ -5,7 +5,7 @@ import { installWorkspacePackages } from '../../../utils/packages'; import { execAndWaitForOutputToMatch, ng } from '../../../utils/process'; import { updateJsonFile, - updateServerFileForWebpack, + updateServerFileForEsbuild, useCIChrome, useCIDefaults, useSha, @@ -62,7 +62,7 @@ export default async function () { build.options.outputMode = undefined; }); - await updateServerFileForWebpack('projects/test-project-two/src/server.ts'); + await updateServerFileForEsbuild('projects/test-project-two/src/server.ts'); } await writeMultipleFiles({ diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts index 531b29a4b0ec..7c819e67693a 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/express-engine-standalone.ts @@ -3,20 +3,14 @@ import { rimraf, writeMultipleFiles } from '../../../utils/fs'; import { findFreePort } from '../../../utils/network'; import { installWorkspacePackages } from '../../../utils/packages'; import { execAndWaitForOutputToMatch, ng } from '../../../utils/process'; -import { updateJsonFile, updateServerFileForWebpack, useSha } from '../../../utils/project'; +import { updateJsonFile, updateServerFileForEsbuild, useSha } from '../../../utils/project'; export default async function () { // forcibly remove in case another test doesn't clean itself up await rimraf('node_modules/@angular/ssr'); const useWebpackBuilder = !getGlobalVariable('argv')['esbuild']; - - if (useWebpackBuilder) { - // `--server-routing` not supported in `browser` builder. - await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); - } else { - await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); - } + await ng('add', '@angular/ssr', '--skip-confirmation', '--skip-install'); if (!useWebpackBuilder) { // Disable prerendering @@ -25,7 +19,7 @@ export default async function () { build.options.outputMode = undefined; }); - await updateServerFileForWebpack('src/server.ts'); + await updateServerFileForEsbuild('src/server.ts'); } await useSha(); diff --git a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static-http-calls.ts b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static-http-calls.ts index d802b0271615..8e7483f77ee4 100644 --- a/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static-http-calls.ts +++ b/tests/legacy-cli/e2e/tests/build/server-rendering/server-routes-output-mode-static-http-calls.ts @@ -84,14 +84,16 @@ export default async function () { const browserDistFolder = join(import.meta.dirname, '../browser'); const angularNodeAppEngine = new AngularNodeAppEngine(); - server.get('/api', (req, res) => res.json({ dataFromAPI: true })); + server.get('/api', (req, res) => { + res.json({ dataFromAPI: true }) + }); - server.get('**', express.static(browserDistFolder, { + server.use(express.static(browserDistFolder, { maxAge: '1y', index: 'index.html' })); - server.get('**', (req, res, next) => { + server.use((req, res, next) => { angularNodeAppEngine.handle(req) .then((response) => response ? writeResponseToNodeResponse(response, res) : next()) .catch(next); @@ -103,7 +105,10 @@ export default async function () { if (isMainModule(import.meta.url)) { const port = process.env['PORT'] || 4000; - server.listen(port, () => { + server.listen(port, (error) => { + if (error) { + throw error; + } console.log(\`Node Express server listening on http://localhost:\${port}\`); }); } diff --git a/tests/legacy-cli/e2e/tests/vite/ssr-entry-express.ts b/tests/legacy-cli/e2e/tests/vite/ssr-entry-express.ts index 18e43f7212a0..60e0c63a7c5a 100644 --- a/tests/legacy-cli/e2e/tests/vite/ssr-entry-express.ts +++ b/tests/legacy-cli/e2e/tests/vite/ssr-entry-express.ts @@ -46,17 +46,22 @@ export default async function () { const browserDistFolder = join(import.meta.dirname, '../browser'); const angularNodeAppEngine = new AngularNodeAppEngine(); - server.use('/api/**', (req, res) => res.json({ hello: 'foo' })); + server.use('/api/{*splat}', (req, res) => { + res.json({ hello: 'foo' }) + }); - server.get('**', express.static(browserDistFolder, { + server.use(express.static(browserDistFolder, { maxAge: '1y', index: 'index.html' })); - server.get('**', (req, res, next) => { - angularNodeAppEngine.handle(req) - .then((response) => response ? writeResponseToNodeResponse(response, res) : next()) - .catch(next); + server.use(async(req, res, next) => { + const response = await angularNodeAppEngine.handle(req); + if (response) { + writeResponseToNodeResponse(response, res); + } else { + next(); + } }); return server; @@ -65,7 +70,11 @@ export default async function () { const server = app(); if (isMainModule(import.meta.url)) { const port = process.env['PORT'] || 4000; - server.listen(port, () => { + server.listen(port, (error) => { + if (error) { + throw error; + } + console.log(\`Node Express server listening on http://localhost:\${port}\`); }); } diff --git a/tests/legacy-cli/e2e/utils/project.ts b/tests/legacy-cli/e2e/utils/project.ts index 42d86bb7a997..ea764bb20314 100644 --- a/tests/legacy-cli/e2e/utils/project.ts +++ b/tests/legacy-cli/e2e/utils/project.ts @@ -205,7 +205,7 @@ export function isPrereleaseCli(): boolean { return (prerelease(getNgCLIVersion())?.length ?? 0) > 0; } -export function updateServerFileForWebpack(filepath: string): Promise { +export function updateServerFileForEsbuild(filepath: string): Promise { return writeFile( filepath, ` @@ -227,13 +227,13 @@ export function updateServerFileForWebpack(filepath: string): Promise { server.set('view engine', 'html'); server.set('views', browserDistFolder); - server.get('**', express.static(browserDistFolder, { + server.use(express.static(browserDistFolder, { maxAge: '1y', - index: 'index.html', + index: false, })); // All regular routes use the Angular engine - server.get('**', (req, res, next) => { + server.use((req, res, next) => { const { protocol, originalUrl, baseUrl, headers } = req; commonEngine @@ -254,7 +254,10 @@ export function updateServerFileForWebpack(filepath: string): Promise { function run(): void { const port = process.env['PORT'] || 4000; const server = app(); - server.listen(port, () => { + server.listen(port, (error) => { + if (error) { + throw error; + } console.log(\`Node Express server listening on http://localhost:\${port}\`); }); }