Using arcgis-webpack-plugin when site runs under a subdirectory

1616
3
07-27-2020 08:32 AM
PatrickGaule
New Contributor

I am trying to use the the webpack plugin (GitHub - Esri/arcgis-webpack-plugin: Webpack plugin for the ArcGIS API for JavaScript ) with our Angular9 application.  I have based it on the example project provided here -> GitHub - Esri/angular-cli-esri-map at arcgis-webpack-angular 

One key difference is that our site runs under a sub-directory rather than a top-level domain.  For instance, our application runs under http://www.example.com/map rather than http://www.example.com/ .  This seems to cause a problem with where the js files are loaded.  For instance, when I hit a page that tries to render the map, I get a bunch of 404 errors when loading the esri javascript files because it is trying to load them from http://www.example.com/49.js rather than http://www.example.com/map/49.js

If I look at http://www.example.com/map/49.js, I see the relevant javascript file.

Is there somewhere to configure the path to our application so that the esri webpack plugin will load files from the subdirectory rather than the top level domain?  This app runs on a multi-tenant server with multiple applications, so I can't host the js files from the top level...

(function(){ (this||window)["webpackJsonp"].registerAbsMids({ 	"esri/core/cookie":"./node_modules/arcgis-js-api/core/cookie.js", 	"esri/identity/IdentityForm":"./node_modules/arcgis-js-api/identity/IdentityForm.js", 	"esri/identity/IdentityManager":"./node_modules/arcgis-js-api/identity/IdentityManager.js", 	"esri/identity/IdentityManagerBase":"./node_modules/arcgis-js-api/identity/IdentityManagerBase.js", 	"esri/identity/IdentityModal":"./node_modules/arcgis-js-api/identity/IdentityModal.js", 	"esri/identity/OAuthCredential":"./node_modules/arcgis-js-api/identity/OAuthCredential.js", 	"esri/identity/OAuthInfo":"./node_modules/arcgis-js-api/identity/OAuthInfo.js", 	"esri/identity/ServerInfo":"./node_modules/arcgis-js-api/identity/ServerInfo.js" }) })(),(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[49],{  /***/ "./node_modules/arcgis-js-api/core/cookie.js": /*!***************************************************!*\   !*** ./node_modules/arcgis-js-api/core/cookie.js ***!   \***************************************************/ /*! no static exports found */ /***/ (function(module, exports, __webpack_require__) {  var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// COPYRIGHT © 2020 Esri // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // This material is licensed for use under the Esri Master License // Agreement (MLA), and is bound by the terms of that agreement. // You may redistribute and use this code without modification, // provided you adhere to the terms of the MLA and include this // copyright notice. // // See use restrictions at http://www.esri.com/legal/pdfs/mla_e204_e300/english // // For additional information, contact: // Environmental Systems Research Institute, Inc. // Attn: Contracts and Legal Services Department // 380 New York Street // Redlands, California, USA 92373 // USA // // email: contracts@esri.com // // See http://js.arcgis.com/4.16/esri/copyright.txt for details.  !(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__.dj.c(module.i),exports], __WEBPACK_AMD_DEFINE_RESULT__ = (function(e,i){Object.defineProperty(i,"__esModule",{value:!0}),i.writeCookie=function(e,i,o){void 0===o&&(o={});var r=o.expires;if("number"==typeof r){var t=new Date;t.setTime(t.getTime()+24*r*60*60*1e3),r=o.expires=t}"string"!=typeof r&&(o.expires=r.toUTCString());var n=e+"="+encodeURIComponent(i);for(var f in o){n+="; "+f;var p=o;!0!==p&&(n+="="+p)}document.cookie=n}}).apply(null, __WEBPACK_AMD_DEFINE_ARRAY__), 				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));  /***/ }),
...

Here is my package.json:

{
  "name""client-app",
  "version""0.0.0",
  "scripts": {
    "ng""ng",
    "start""ng serve",
    "build""ng build --watch --extract-css",
    "build-prod""ng build --prod --output-hashing=none",
    "test""ng test",
    "test-headless""ng test --watch=false --browsers=ChromeHeadless",
    "test-coverage""ng test --watch=false --browsers=ChromeHeadless --codeCoverage=true ",
    "test-headless-firefox""ng test --watch=false --browsers=FirefoxHeadless",
    "lint""ng lint",
    "e2e""ng e2e",
    "bundle-report""ng build --prod --stats-json && webpack-bundle-analyzer wwwroot/application/dist/stats.json"
  },
  "private"true,
  "dependencies": {
    "@angular/animations""^9.0.5",
    "@angular/cdk""^9.1.1",
    "@angular/common""^9.0.5",
    "@angular/compiler""^9.0.5",
    "@angular/core""^9.0.5",
    "@angular/forms""^9.0.5",
    "@angular/localize""^9.0.5",
    "@angular/platform-browser""^9.0.5",
    "@angular/platform-browser-dynamic""^9.0.5",
    "@angular/router""^9.0.5",
    "@fcsa/nitro-angular""~0.12.0",
    "@fcsa/nitro-style""~0.18.0",
    "@fortawesome/fontawesome-pro""^5.12.1",
    "@ng-bootstrap/ng-bootstrap""^5.3.0",
    "@okta/okta-angular""^1.4.0",
    "moment""^2.27.0",
    "rename-webpack-plugin""^2.0.0",
    "rxjs""~6.5.4",
    "terraformer""^1.0.10",
    "terraformer-arcgis-parser""^1.1.0",
    "tslib""^1.11.1",
    "zone.js""~0.10.2"
  },
  "devDependencies": {
    "@angular-builders/custom-webpack""^8.4.1",
    "@angular-devkit/build-angular""^0.900.5",
    "@angular/cli""^9.0.5",
    "@angular/compiler-cli""^9.0.5",
    "@angular/language-service""^9.0.5",
    "@arcgis/webpack-plugin""^4.16.2",
    "@types/arcgis-js-api""^4.14.0",
    "@types/geojson""^7946.0.7",
    "@types/jasmine""^3.5.7",
    "@types/jasminewd2""~2.0.3",
    "@types/node""^13.7.7",
    "codelyzer""^5.2.1",
    "jasmine-core""^3.5.0",
    "jasmine-spec-reporter""~4.2.1",
    "karma""^4.4.1",
    "karma-chrome-launcher""^3.1.0",
    "karma-coverage-istanbul-reporter""^2.1.1",
    "karma-jasmine""^3.1.1",
    "karma-jasmine-html-reporter""^1.5.2",
    "prettier""^1.19.1",
    "protractor""^5.4.3",
    "ts-node""^8.6.2",
    "tslint""^6.0.0",
    "typescript""~3.7.5"
  }
}

Here is my angular.json:

{
  "$schema""./node_modules/@angular/cli/lib/config/schema.json",
  "version"1,
  "newProjectRoot""projects",
  "projects": {
    "ExampleProject": {
      "root""",
      "sourceRoot""clientApp",
      "projectType""application",
      "prefix""pol",
      "schematics": {
        "@schematics/angular:component": {
          "style""scss"
        }
      },
      "architect": {
        "build": {
          "builder""@angular-builders/custom-webpack:browser",
          "options": {
            "outputPath""wwwroot/dist/",
            "index""clientApp/index.html",
            "main""clientApp/main.ts",
            "polyfills""clientApp/polyfills.ts",
            "tsConfig""tsconfig.app.json",
            "customWebpackConfig": {
              "path""./webpack.config.js"
            },

            "aot"false,
            "assets": [
              "clientApp/favicon.ico",
              "clientApp/assets",
              "clientApp/web.config",
              {
                "glob""**/*",
                "input""node_modules/@fcsa/nitro-style/dist/nitro-style/assets",
                "output""./assets"
              }
            ],
            "styles": [
              "node_modules/@fortawesome/fontawesome-pro/css/fontawesome.css",
              "node_modules/@fortawesome/fontawesome-pro/css/regular.css",
              "node_modules/@fortawesome/fontawesome-pro/css/solid.css",
              "node_modules/@angular/cdk/overlay-prebuilt.css",
              "node_modules/@fcsa/nitro-style/dist/nitro-style/style.scss",
              "clientApp/styles.scss"
            ],
            "scripts": [],
            "es5BrowserSupport"true,
            "stylePreprocessorOptions": {
              "includePaths": ["node_modules/@fcsa/nitro-style/dist"]
            }
          },
          "configurations": {
            "production": {
              "fileReplacements": [
                {
                  "replace""clientApp/environments/environment.ts",
                  "with""clientApp/environments/environment.prod.ts"
                }
              ],
              "optimization"true,
              "outputHashing""all",
              "sourceMap"false,
              "extractCss"true,
              "namedChunks"false,
              "aot"true,
              "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""clientApp:build"
          },
          "configurations": {
            "production": {
              "browserTarget""clientApp:build:production"
            }
          }
        },
        "extract-i18n": {
          "builder""@angular-devkit/build-angular:extract-i18n",
          "options": {
            "browserTarget""clientApp:build"
          }
        },
        "test": {
          "builder""@angular-devkit/build-angular:karma",
          "options": {
            "main""clientApp/test.ts",
            "polyfills""clientApp/polyfills.ts",
            "tsConfig""tsconfig.spec.json",
            "karmaConfig""karma.conf.js",
            "assets": ["clientApp/favicon.ico""clientApp/assets"],
            "styles": ["clientApp/styles.scss"],
            "scripts": [],
            "stylePreprocessorOptions": {
              "includePaths": ["node_modules/@fcsa/nitro-style/dist"]
            }
          }
        },
        "lint": {
          "builder""@angular-devkit/build-angular:tslint",
          "options": {
            "tsConfig": [
              "tsconfig.app.json",
              "tsconfig.spec.json",
              "tsconfig.json"
            ],
            "exclude": ["**/node_modules/**"]
          }
        }
      }
    }
  },
  "defaultProject""clientApp"
}

Here is my webpack.config.js

const ArcGISPlugin = require('@arcgis/webpack-plugin');

module.exports = {
  plugins: [new ArcGISPlugin({
    features: {
      '3d': false
    },
  })],
  node: {
    process: false,
    global: false,
    fs: "empty"
  }
};
0 Kudos
3 Replies
ReneRubalcava
Frequent Contributor

Just testing this out with a regular webpack build and I think this is working.

Update your webpack config like this.

// webpack.config.js
output: {
  path: path.resolve(__dirname, 'dist/map'),
  filename: "[name].[chunkhash].js",
  publicPath: "/map/"
},

// plugins
new ArcGISPlugin({
  features: {
    "3d": false
  },
  environment: {
    root: "/map",
  }
}),

// You could modify the HtmlWebPackPlugin
// to output the index.html to the
// root of the output
new HtmlWebPackPlugin({
  title: "ArcGIS Template Application",
  template: "./src/index.html",
  filename: "../index.html", // up one from /map/
  favicon: "./src/assets/favicon.ico",
  chunksSortMode: "none",
  inlineSource: ".(css)$"
}),

In testing, it looks like all paths in the build will refer to the /map/ directory and all files will be copied there. The index.html is also copied there, but, I noted in the snippet that you can define the correct place for it.

0 Kudos
PatrickGaule
New Contributor

Thanks so much Rene!. That seems to have fixed that issue, but I have uncovered another problem.  Our map now loads, but I get a bunch of errors along the following lines:

dojo.js:6 DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://.../arcgis-js-api/layers/support/TileInfo.js' failed to load.

dojo.js:6 DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https://.../arcgis-js-api/views/2d/ViewState.js' failed to load.
dojo.js:6 DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'https:/.../arcgis-js-api/layers/support/TileInfo.js' failed to load.

Initial research points to this thread (Error loading Pipeline.js - Angular & ArcGIS API For JavaScript ), where you actually responded and mentioned that "somewhere you need to set up the worker loader url configuration."  I did see this mentioned in the github documentation for the webpack plugin, which refers to is as an "external loader." (GitHub - Esri/arcgis-webpack-plugin: Webpack plugin for the ArcGIS API for JavaScript ).  I am just so confused as to where I am supposed to reference the "external loader" code, that is shown below:

Does this "external loader" need to be tied into our webpack.config.js somehow?  Does this code just need to be included in my angular project somewhere, and referenced at runtime (looks to be what this guy is doing esri-webpack/esri-map.component.ts at master · ronavraham/esri-webpack · GitHub )

Is there a working example of using this "external loader" with an angular project?  It doesn't seem to be used in the sample angular webpack project.

import esriConfig from "esri/config";const DEFAULT_WORKER_URL = "https://js.arcgis.com/4.12/";const DEFAULT_LOADER_URL = `${DEFAULT_WORKER_URL}dojo/dojo-lite.js`;esriConfig.workers.loaderUrl = DEFAULT_LOADER_URL;esriConfig.workers.loaderConfig = {  baseUrl: `${DEFAULT_WORKER_URL}dojo`,  packages: [    { name: "esri", location: `${DEFAULT_WORKER_URL}esri` },    { name: "dojo", location: `${DEFAULT_WORKER_URL}dojo` },    { name: "dojox", location: `${DEFAULT_WORKER_URL}dojox` },    { name: "dstore", location: `${DEFAULT_WORKER_URL}dstore` },    { name: "moment", location: `${DEFAULT_WORKER_URL}moment` },    { name: "@dojo", location: `${DEFAULT_WORKER_URL}@dojo` },    {      name: "cldrjs",      location: `${DEFAULT_WORKER_URL}cldrjs`,      main: "dist/cldr"    },    {      name: "globalize",      location: `${DEFAULT_WORKER_URL}globalize`,      main: "dist/globalize"    },    {      name: "maquette",      location: `${DEFAULT_WORKER_URL}maquette`,      main: "dist/maquette.umd"    },    {      name: "maquette-css-transitions",      location: `${DEFAULT_WORKER_URL}maquette-css-transitions`,      main: "dist/maquette-css-transitions.umd"    },    {      name: "maquette-jsx",      location: `${DEFAULT_WORKER_URL}maquette-jsx`,      main: "dist/maquette-jsx.umd"    },    { name: "tslib", location: `${DEFAULT_WORKER_URL}tslib`, main: "tslib" }  ]};
NilsBabel1
Occasional Contributor

Any progress with this?  I think I am in the exact same boat.  I have setup the sample on github and have the map working but as soon as I try and do anything else (i.e. add a feature layer) I get the Error loading Pipeline.js.  I've also seen the github site and other forum posts about default workers but can't figure out how to get it to work.

0 Kudos