angular-builders icon indicating copy to clipboard operation
angular-builders copied to clipboard

Unable to change devServer sockPath

Open mistic100 opened this issue 3 years ago • 7 comments

Describe the Bug

I try to override the devServer.sockPath to suit the specific configuration of our dev stations. But it looks like this part of the configuration is read before @angular-builders/dev-server has a chance to modify it.

I actually put logs here https://github.com/webpack/webpack-dev-server/blob/v3.11.2/lib/utils/addEntries.js#L31 and is called before my custom webpack config.

// webpack.custom.js
module.exports = (config) => {
  const pkg = require(process.cwd() + '/package.json');

  config.devServer.sockPath = '/' + pkg.sglk.suffixAppPath + config.devServer.sockPath;    

  return config;
};

Environment


Libs
- @angular/core version: 112.3
- @angular-devkit/build-angular version: 0.1102.2
- @angular-builders/dev-server version: 7.3.1
- webpack 4 / webpack-dev-server 3

mistic100 avatar Feb 26 '21 16:02 mistic100

It looks similar to #86 but that was 3 years agao :)

mistic100 avatar Feb 26 '21 16:02 mistic100

Could you please share your angular.json? A minimal reproduction would be very useful as well.

just-jeb avatar Mar 21 '21 13:03 just-jeb

angular.json
{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "version": 1,
  "newProjectRoot": "projects",
  "projects": {
    "app": {
      "projectType": "application",
      "schematics": {},
      "root": "",
      "sourceRoot": "src",
      "prefix": "app",
      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "./webpack.custom.config.js"
            },
            "outputPath": "dist/app",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "tsconfig.app.json",
            "aot": true,
            "assets": [
              "src/favicon.ico",
              "src/assets"
            ],
            "styles": [
              "src/styles.css"
            ],
            "scripts": []
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-builders/custom-webpack:dev-server",
          "options": {
            "browserTarget": "app:build"
          },
          "configurations": {
            "production": {
              "browserTarget": "app:build:production"
            }
          }
        }
      }
    }
  },
  "defaultProject": "app"
}
webpack.custom.config.js
const webpack = require('webpack');
const pkg = require('./package.json');

module.exports = (config) => {
    config.plugins.push(
        new webpack.DefinePlugin({
            APP_VERSION: JSON.stringify(pkg.version),
        })
    );

    config.devServer.sockPath = '/custom-dir' + config.devServer.sockPath;  

    return config;
};

the DefinePlugin is just here to validate the config is applied.


This is only a starter application created with ng new app and using @angular-builders/custom-webpack.

On a standard Angular app the livereload socket is located at :
localhost:4200/sockjs-node

With the above configuration the app still tries to connect to the same URL but in reality the sockjs server is located at :
localhost:4200/custom-dir/sockjs-node (you can open it in a new tab, it is really there)


Motivation : We use a reverse proxy when developping on our workstations, so we access local.dev/application-name instead of localhost:port.

The configuration is something like

ProxyPass /application-name http://localhost:4200
ProxyPassReverse /application-name http://localhost:4200

With Angular 11 something changed with how publicHost and servePath are used to generate the SockJS path and the only solution I found is to override it. And it almost works ;-)

mistic100 avatar Mar 21 '21 17:03 mistic100

Note: I didn't put any conf related to the reverse proxy on my example because the issue is not directly linked, with or without RP the issue is the same : the override of devServer.sockPath is only partially applied.

mistic100 avatar Mar 21 '21 17:03 mistic100

@mistic100 Can you share your configuration? , I used a similar development method. sockpath replacement failed.

Host: app.test

app.test/ => angular ssr app
app.test/app => angular spa app // i try modify sockpath is not work
app.test/api => nest api

StringKe avatar Apr 24 '21 03:04 StringKe

I already did, two messages above (click the file names with the little triangle)

mistic100 avatar Apr 24 '21 09:04 mistic100

I already did, two messages above (click the file names with the little triangle)

I tried the config file you said.

With Angular 11 something changed with how publicHost and servePath are used to generate the SockJS path and the only solution I found is to override it. And it almost works ;-)

but,I don't know how to set publicHost and servePath two values.

My nginx configuration file is like this, and the sockjs-node path of the spa app has not changed.

location ^~ /api/ {
    rewrite /api/(.+)$ /$1 break;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:7001/;
}

# spa app
location ^~ /design/page/ {
    rewrite /design/page/(.+)$ /$1 break;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:7002;
}

# ssr app
location ^~ / {
    rewrite /(.+)$ /$1 break;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_pass http://127.0.0.1:7000/;
}

angular.json

{
  "version": 1,
  "cli": {
    "defaultCollection": "@nrwl/angular",
    "analytics": false
  },
  "defaultProject": "site",
  "schematics": {
    "@nrwl/angular": {
      "application": {
        "linter": "eslint"
      },
      "library": {
        "linter": "eslint"
      },
      "storybook-configuration": {
        "linter": "eslint"
      }
    },
    "@nrwl/angular:application": {
      "style": "scss",
      "linter": "eslint",
      "unitTestRunner": "jest",
      "e2eTestRunner": "cypress"
    },
    "@nrwl/angular:library": {
      "style": "scss",
      "linter": "eslint",
      "unitTestRunner": "jest"
    },
    "@nrwl/angular:component": {
      "style": "scss"
    }
  },
  "projects": {
    "site": {
      "projectType": "application",
      "root": "apps/site",
      "sourceRoot": "apps/site/src",
      "prefix": "diandiantu",
      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath": "dist/site/browser",
            "index": "apps/site/src/index.html",
            "main": "apps/site/src/main.ts",
            "polyfills": "apps/site/src/polyfills.ts",
            "tsConfig": "apps/site/tsconfig.app.json",
            "aot": true,
            "assets": ["apps/site/src/favicon.ico", "apps/site/src/assets"],
            "styles": ["apps/site/src/styles.scss"],
            "scripts": [],
            "customWebpackConfig": {
              "path": "apps/site/webpack.config.js"
            }
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "apps/site/src/environments/environment.ts",
                  "with": "apps/site/src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-builders/custom-webpack:dev-server",
          "options": {
            "browserTarget": "site:build",
            "disableHostCheck": true,
            "host": "0.0.0.0",
            "port": 7000
          },
          "configurations": {
            "production": {
              "browserTarget": "site:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "site:build"
          }
        },
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": [
              "apps/site/src/**/*.ts",
              "apps/site/src/**/*.html"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "outputs": ["coverage/apps/site"],
          "options": {
            "jestConfig": "apps/site/jest.config.js",
            "passWithNoTests": true
          }
        },
        "server": {
          "builder": "@angular-builders/custom-webpack:server",
          "options": {
            "outputPath": "dist/site/server",
            "main": "apps/site/server.ts",
            "tsConfig": "apps/site/tsconfig.server.json"
          },
          "configurations": {
            "production": {
              "outputHashing": "media",
              "fileReplacements": [
                {
                  "replace": "apps/site/src/environments/environment.ts",
                  "with": "apps/site/src/environments/environment.prod.ts"
                }
              ],
              "sourceMap": false,
              "optimization": true
            }
          }
        },
        "serve-ssr": {
          "builder": "@nguniversal/builders:ssr-dev-server",
          "options": {
            "browserTarget": "site:build",
            "serverTarget": "site:server"
          },
          "configurations": {
            "production": {
              "browserTarget": "site:build:production",
              "serverTarget": "site:server:production"
            }
          }
        },
        "prerender": {
          "builder": "@nguniversal/builders:prerender",
          "options": {
            "browserTarget": "site:build:production",
            "serverTarget": "site:server:production",
            "routes": ["/"]
          },
          "configurations": {
            "production": {}
          }
        }
      }
    },
    "api": {
      "root": "apps/api",
      "sourceRoot": "apps/api/src",
      "projectType": "application",
      "architect": {
        "build": {
          "builder": "@nrwl/node:build",
          "outputs": ["{options.outputPath}"],
          "options": {
            "outputPath": "dist/apps/api",
            "main": "apps/api/src/main.ts",
            "tsConfig": "apps/api/tsconfig.app.json",
            "assets": ["apps/api/src/assets"]
          },
          "configurations": {
            "production": {
              "optimization": true,
              "extractLicenses": true,
              "inspect": false,
              "fileReplacements": [
                {
                  "replace": "apps/api/src/environments/environment.ts",
                  "with": "apps/api/src/environments/environment.prod.ts"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@nrwl/node:execute",
          "options": {
            "buildTarget": "api:build"
          }
        },
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["apps/api/**/*.ts"]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "outputs": ["coverage/apps/api"],
          "options": {
            "jestConfig": "apps/api/jest.config.js",
            "passWithNoTests": true
          }
        }
      }
    },
    "design-page": {
      "projectType": "application",
      "root": "apps/design/page",
      "sourceRoot": "apps/design/page/src",
      "prefix": "diandiantu",
      "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath": "dist/apps/design/page",
            "index": "apps/design/page/src/index.html",
            "main": "apps/design/page/src/main.ts",
            "polyfills": "apps/design/page/src/polyfills.ts",
            "tsConfig": "apps/design/page/tsconfig.app.json",
            "aot": true,
            "assets": [
              "apps/design/page/src/favicon.ico",
              "apps/design/page/src/assets"
            ],
            "styles": ["apps/design/page/src/styles.scss"],
            "scripts": [],
            "customWebpackConfig": {
              "path": "apps/design/page/webpack.config.js"
            }
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace": "apps/design/page/src/environments/environment.ts",
                  "with": "apps/design/page/src/environments/environment.prod.ts"
                }
              ],
              "optimization": true,
              "outputHashing": "all",
              "sourceMap": false,
              "namedChunks": false,
              "extractLicenses": true,
              "vendorChunk": false,
              "buildOptimizer": true,
              "budgets": [
                {
                  "type": "initial",
                  "maximumWarning": "2mb",
                  "maximumError": "5mb"
                },
                {
                  "type": "anyComponentStyle",
                  "maximumWarning": "6kb",
                  "maximumError": "10kb"
                }
              ]
            }
          }
        },
        "serve": {
          "builder": "@angular-builders/custom-webpack:dev-server",
          "options": {
            "browserTarget": "design-page:build",
            "disableHostCheck": true,
            "host": "0.0.0.0",
            "port": 7002
          },
          "configurations": {
            "production": {
              "browserTarget": "design-page:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder": "@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget": "design-page:build"
          }
        },
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": [
              "apps/design/page/src/**/*.ts",
              "apps/design/page/src/**/*.html"
            ]
          }
        },
        "test": {
          "builder": "@nrwl/jest:jest",
          "outputs": ["coverage/apps/design/page"],
          "options": {
            "jestConfig": "apps/design/page/jest.config.js",
            "passWithNoTests": true
          }
        }
      }
    },
    "interfaces-api": {
      "root": "libs/interfaces/api",
      "sourceRoot": "libs/interfaces/api/src",
      "projectType": "library",
      "architect": {
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["libs/interfaces/api/**/*.ts"]
          }
        }
      }
    },
    "interfaces-site": {
      "root": "libs/interfaces/site",
      "sourceRoot": "libs/interfaces/site/src",
      "projectType": "library",
      "architect": {
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["libs/interfaces/site/**/*.ts"]
          }
        }
      }
    },
    "interfaces-design": {
      "root": "libs/interfaces/design",
      "sourceRoot": "libs/interfaces/design/src",
      "projectType": "library",
      "architect": {
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["libs/interfaces/design/**/*.ts"]
          }
        }
      }
    },
    "tools-helper": {
      "root": "libs/tools/helper",
      "sourceRoot": "libs/tools/helper/src",
      "projectType": "library",
      "architect": {
        "lint": {
          "builder": "@nrwl/linter:eslint",
          "options": {
            "lintFilePatterns": ["libs/tools/helper/**/*.ts"]
          }
        }
      }
    }
  }
}

the design-app webpack config

const { addTailwindPlugin } = require('@ngneat/tailwind');
const tailwindConfig = require('../../../tailwind.config.js');

module.exports = (config) => {
  addTailwindPlugin({
    webpackConfig: config,
    tailwindConfig,
  });
  config.devServer.sockPath = '/design/page' + config.devServer.sockPath;
  return config;
};

StringKe avatar Apr 24 '21 11:04 StringKe