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

15k views Asked by At

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

3

There are 3 answers

3
tcdevens On BEST ANSWER

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="/">
0
Hiep Tran On

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

3
Miloš Stanić On

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.