3

We are rewriting our existing Angular 8 PWA to Vuejs and we are facing a few issues concerning the build process. (We are not here to discuss the reasons of that choice nor anyone's opinion on it)

Our app must be built for different customers with specific assets for each customers (manifest.json file, icons and images).

In Angular, we accomplish file replacements by defining rules in angular.json file using the fileReplacements key like this:

"configurations": {
        "production-customer-a": {
          "fileReplacements": [
            {
              "replace": "src/manifest.json",
              "with": "src/environments/customer-a/assets/manifest.json"
            },
          ],
          // Some more json stuff

We tried to implement a similar process in our vue app in vue.config.js using webpack's NormalModuleReplacementPlugin like this:

configureWebpack: () => {
let plugins;
switch (customer) {
  case customer-a:
    plugins = [
      new NormalModuleReplacementPlugin(
        /\.\.\/public\/manifest\.json/,
        "../environments/customer-a/assets/manifest.json"
      ),
     // Some more config

It works great if the concerned files are actually referenced in the app using its url at build. Let me explain with an example:

<img src="@/assets/myImageWhichShouldBeReplacedAtBuild.png" /> /* Will actually be replaced and the dist folder will contain the file properly */
<img src="@/assets/myImageWhichShouldBeReplacedAtBuildButIsBase64EncodedWithWebpackUrlLoader.png" /> /* Will be replaced as the base64 string but the dist folder wont contain the file and might be an issue if the image is to be used by files like manifest.json */

The later is not a complete issue since we can override webpack's url-loader in vue.config.js like explained here. But still a good catch to know about.

Since we don't reference files like manifest.json or favicon.ico in the Vue templates, those files are not replaced.

Is there anyway to make sure every file we need will be replaced at build to obtain the same result as with Angular's angular.json config file ? Maybe using something different than NormalModuleReplacementPlugin ?

Pierre Burton
  • 1,954
  • 2
  • 13
  • 27

1 Answers1

1

So for any lost soul that comes around here, we managed to find a proper solution.

We got rid of webpack's NormalModuleReplacementPlugin and worked in combination with a task runner (gulp, in our case) and Vue static assets handling.

Since the concerned assets where always the same, we put the default ones in the public folder of the solution and recreated the same structure in our environments folders for each customer.

-public
--img
---icons

-environments
--customer
---img
----icons

Making use of Vue's URL transform rule, we referenced all our assets in the app with an absolute path, so the files won't go through webpack's processing. After the build, we run our gulpfile that takes all the customer's assets (passed as argument) and override them in the dist folder.

gulpfile.js:

const gulp = require('gulp');
const yargs = require('yargs').argv;

gulp.task('moveassets', () => {
  return gulp.src(`environments/${yargs.customer}/**/**/**`)
    .pipe(gulp.dest('dist'));
})

package.json script:

"build:customer": "vue-cli-service build && gulp moveassets --customer customer"

It might cause a bit of trouble with cache handling since webpack would have put hashes to files, but Angular is not doing it also so it won't change our habits.

Pierre Burton
  • 1,954
  • 2
  • 13
  • 27