3

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

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:

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?

Nitramk
  • 1,542
  • 6
  • 25
  • 42

1 Answers1

6

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.

smeel
  • 123
  • 6
ZeroKoll
  • 76
  • 2
  • Not sure if I'm doing wrong, but I can't seem to get this to work at all. – Jeremy Lindblom Mar 08 '18 at 23:21
  • @JeremyLindblom use: __webpack_require__.p = window.config.basePath; the config object on the window sets a property "basePath" while the code in the app module sets the rootPath. Therefore you get an "undefined" value for your __webpack_require__.p property which causes the APIs to fail – smeel May 30 '18 at 07:27
  • This seems to be not valid anymore, as the `__webpack_require__.p` and all the surrounding code is wrapped in the isolated scope of anonymous function: `(function(modules) { ..... })([]);`, so that variable is not global anymore. – carecki Oct 18 '19 at 22:17