What is best way to go about replacing 'deployUrl' in angular.json for v13?
Asked Answered
B

3

13

I'm currently in the process of upgrading my app from v12 to v13 and noticed this warning pop up:

Option "deployUrl" is deprecated: Use "baseHref" option, "APP_BASE_HREF" DI token or a combination of both instead. For more information, see https://angular.io/guide/deployment#the-deploy-url.

After digging into it a little more, none of the 'baseHref' or APP_BASE_REF options really work for my setup so I'm wondering if I'm using them incorrectly or if there isn't a good way to go about replacing it

Here's a snippet of the app config from angular.json:

    "dashboard": {
      "projectType": "application",
      "root": "apps/dashboard",
      "sourceRoot": "apps/dashboard/src",
      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "allowedCommonJsDependencies": [],
            "outputPath": "../dist/dashboard/",
            "deployUrl": "/dist/dashboard/",
            "index": "apps/dashboard/src/index.html",
            "main": "apps/dashboard/src/main.ts",
            "tsConfig": "apps/dashboard/tsconfig.app.json",
            "polyfills": "apps/dashboard/src/polyfills.ts",
            "styles": [
              "apps/dashboard/src/styles.scss"
            ],
            "scripts": [],
            "stylePreprocessorOptions": {
              "includePaths": [
                "libs/assets/styles"
              ]
            },
            "aot": false,
            "vendorChunk": true,
            "extractLicenses": false,
            "buildOptimizer": false,
            "sourceMap": true,
            "optimization": false,
            "namedChunks": true
          },
          "configurations": {
            "production": {
              "aot": true,
              "buildOptimizer": true,
              "extractLicenses": true,
              "fileReplacements": [
                {
                  "replace": "apps/dashboard/src/environments/environment.ts",
                  "with": "apps/dashboard/src/environments/environment.prod.ts"
                }
              ],
              "namedChunks": false,
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "vendorChunk": false
            },
            "es5": {
              "tsConfig": "apps/dashboard/tsconfig.es5.json"
            }
          },
          "defaultConfiguration": ""
        }
      }
    }

Snippet of routing file:

export const DashboardRoutes: Routes = [
    { path: '', pathMatch: 'full', redirectTo: '/dashboard' },
    {
        path: 'dashboard',
        data: {
            label: 'Dashboard',
            appBase: true
        },
        children: [
            // this is a child so we can load the component in same router-outlet
            {
                path: '',
                loadChildren: () => import('./dashboard/dashboard.module').then(m => m.DashboardModule),
                data: {
                    authorizedRoles: ['member'],
                }
            },
            // ...other children
        ]
    }
]

I've tried changing deployUrl to baseHref and that works, kind of - It changes the main page from localhost/dashboard to localhost/dist/dashboard/dashboard (obviously not right) and just putting an empty string or "/" doesn't load the app correctly (looks at dist/ vs dist/dashboard like it should)

Worth noting that my index.html does use <base href="/" /> and APP_BASE_HREF is not overridden in the app module providers

Bound answered 31/3, 2022 at 15:56 Comment(4)
What does your router code look like? you might want to redirect from the base "/" to your dashboard urlSinglehearted
I added a snippet of the routes, that's essentially what i'm doing atmBound
Not sure if the route matters that much, but try changing the redirect from /dashboard to just dashboard. Also, you do not have a component for your dashboard route. Does that even work?Singlehearted
Changing the redirect doesn't change the behavior at all (with or without the deployUrl) and fwiw I haven't had much luck with trying to alter the route configuration s.t. it actually loads correctly. Also the dashboard route lazy loads the dashboard module, which in turn has a route defined with the dashboard component (trying to only load what we need as much as possible)Bound
B
7

Ended up finding something to replace this with:

  • Replaced "deployUrl" with "baseHref" in angular.json
  • Added the APP_BASE_HREF override in app.module
    • i.e { provide: APP_BASE_HREF, useValue: '/' }
  • Replaced any hrefs in index.html that referenced the dist (output) folder
    • e.g replaced 'dist/assets/{some_asset}' with '../assets/{some_asset'}'
  • index.html still uses <base href="/">
Bound answered 18/4, 2022 at 15:44 Comment(3)
"Replaced any hrefs in index.htm...." but the index.html you are referring to is the "template", there are no assets listed in there, or did I get that wrong?Clinkerbuilt
In my case I had some static assets defined inside my index.html (fonts, images, etc) that just needed their relative paths changedBound
I tried this, but that last bullet isn't true. If I set baseHref : '/client/' in angular.json, it automatically changes the index.html so that <base href="/client/">. How did you get it to leave the <base> tag alone in index.html?Samaniego
L
6

This is a problem with Angular 13+

Found a solution here: https://github.com/angular/angular-cli/issues/22113#issuecomment-1004279867

You should put following code in your main.ts file:

declare var  __webpack_public_path__: string;
__webpack_public_path__ = 'valueFormerlyAssignedUsing_deployUrl';

Replace valueFormerlyAssignedUsing_deployUrl with your path to folder containing chunks.

Landlord answered 7/10, 2022 at 11:34 Comment(3)
Keep in mind that this value is only used inside the generated scripts/styles. It has no effect on the path in the src attribute of the script tag in the output index.html, so one needs an extra step to rewrite those as well. This is what step 2 in Hiep Tran's answer does.Maharashtra
This seems like the easiest migration away from Angular's deployUrl, and although I will apply it to our project, I must say I'm a bit reluctant because it appears a bit hacky. What if Webpack decides to rename this __webpack_public_path__ variable?Maharashtra
I imagine that this is where a custom builder like ngx-build-plus comes in. This makes it possible to extend the standard angular build options with options from Webpack itself, like output.publicPathMaharashtra
J
0

My current Angular version is 14, since Angular 13 despricated deployUrl.

Cause trouble if you using CDN cache but your app running on different domain like cloud server or cloud function.

here is the solution step by step:

  1. delete deployUrl, no need to change it to baseHref, we keep it default

  2. replace url to load it manually by replace-file.js:

const replace = require('replace-in-file');

const prefix = 'https://your-cdn.com/assets';

const action2options = {
  files: path.join(process.cwd(), '/dist/browser/index.html'),
  from: [/<script src="(.*?)"/g],
  to: [`<script src="${prefix}$1"`],
};


replace(action2options)
  .then(results => {
    // console.log('Replacement results:', results);
  })
  .catch(error => {
    console.error('Error occurred:', error);
  });
  1. load the chunk using your assets CDN by add this line to main.ts (if use universal, add it to main.server.ts too:
// main.ts add it
// main.server.ts add it too if use universal
// https://github.com/angular/angular-cli/issues/22113#issuecomment-1004279867
declare var __webpack_public_path__: string;
__webpack_public_path__ = 'https://your-cdn.com/assets';

if you need change link by environment, use this to detect:

// angular.json => add to build -> scripts file

            {
                "input": "src/environments/replacer-build.js",
                "inject": false,
                "bundleName": "replacer-build.development"
              }
// update to production build too:
  "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],

after that you can detect it in replace-file.js by this:

const fs = require('fs');

const files = fs.readdirSync(path.join(process.cwd(), '/dist/browser')).filter(file => {
  return file.match(/^replacer-build\.(development|production|staging)\.js$/);
});

let env = '';
let assetUrl = '';
if (files.length > 0) {
  const filename = files[0];
  if (filename.includes('development')) {
    env = 'development';
    assetUrl = 'http://localhost:4200/';
  else if (filename.includes('production')) {
    env = 'production';
    assetUrl = 'https://your-cdn.com/assets';
  }
}


console.log(`The current environment is ${env} and assetURL replace to:`, assetUrl);

after that you can load your system on your server but assets by CDN

Jitney answered 8/7, 2023 at 13:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.