Changing Angular 5 publish url at runtime

2020-06-06 02:41发布

问题:

I want to build an Angular 5 app once, and then publish it to different addresses, for example to:

  • https://sub1.example.com/myapp1
  • https://sub2.example.com/myapp2
  • https://sub3.example.com/myapp3

By default, Angular will assume that all files are hosted in / so when i access index.html, it will load scripts such as https://sub1.example.com/vendor.bundle.js which will 404 because it's deploy to /myapp1/vendor.bundle.js (to make it slightly more complex, I'm actually loading the files from a CDN from a separate domain, but I don't think this affects the question):

Angular 5 allows me to run:

ng build --deploy-url "https://example.com/myapp1"

This will modify the inline.bundle.js and set the following:

/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "https://example.com/myapp1";

This in turn will make sure that scripts are loaded from the proper path.

However, this is a compile time switch, and I want to configure this either at deploy-time or at runtime.

I've read various suggestions, such as:

  • How do I set the deployUrl at runtime in Angular - This does not seem to work any more. The referenced variable __webpack_public_path__ does not exist anywhere in the code after I run ng build.
  • Setting server url dynamically during runtime in AngularJs app using value during-runtime-in-angularjs-app-using-value - This only applies to Angular .

My current workaround is to update the variable __webpack_require__.p at deploy-time, but this is extremly error-prone since this variable at this point is minimized to something like "n.p" and relying on an internal implementation detail.

What would be the proper approach to do this?

回答1:

Setting the deployUrl setting in .angular-cli.json, or passing in the --deploy-url to the build command does 2 things. It makes sure that the script includes in the index.html file are using that as the base, and it sets a variable that makes sure that webpack adds that as the "base path" for any lazy loaded modules. That much we agree on I guess, and figuring out where to load the scripts from in the html is pretty simple. However, setting the path that webpack should use is a bit more tricky... The value used by webpack is not named __webpack_public_path__ as mentioned in the linked suggestion and in the documentation.

You even mention the solution yourself when you say that setting the --deploy-url causes the following

__webpack_require__.p = "https://example.com/myapp1"; 

So, instead of setting the __webpack_public_path__ at runtime, as mentioned explained in the documentation, you have to set the __webpack_require__.p property.

The easiest way to do this is to just set it in the app.module.ts file. Doing something like this should work in your scenario

index.html

<script>
  window.config = { basePath: 'https://sub1.example.com/myapp1' }
</script>`

app.module.ts

// imports etc...

declare var __webpack_require__: any;
declare var config;
__webpack_require__.p = window.config.basePath;

@NgModule({})
...

This will make sure that the __webpack_require__.p property is set to the configured value on load.

In this case I just added the configured value as a config variable on the window object, but you can fetch it from wherever you want. And to keep it simple, I just assumed the value would always be there... You might want to have a fallback in case the config object isn't available, or the basePath property isn't set.