问题
I have a Play
application. The UI
of the application is in Angular
. I have created a folder ui
which is the top level Angular
directory.
build.sbt
`ui-dev-build` := {
implicit val UIroot = baseDirectory.value / "ui"
if (runDevBuild != Success) throw new Exception("Oops! UI Build crashed.")
}
def runDevBuild(implicit dir: File): Int = ifUiInstalled(runScript("npm run build"))
package.json
"build": "ng build --output-path ../public/ui",
When the Angular
application is build, I transfer the output to the public
folder of the Play
framework. From there, Play
transfers the contacts of the public
folder to target
folder for deployment. In the index.html
(homepage html file), I access angular
by including the scripts created in Angular
build.
<script src="@routes.Assets.versioned("ui/runtime.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/vendor.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/styles.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/main.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/scripts.js")" type="text/javascript"></script>
This works fine.
I want to use ng-ace2-editor
in my application - https://github.com/fxmontigny/ng2-ace-editor. I have added it in package.json
- "ng2-ace-editor": "0.3.9"
and I can see that ng2-ace-editor
directory is present in node_modules
.
When I run the application, I get error
GET http://localhost:9000/mode-html.js net::ERR_ABORTED 404 (Not Found)
exports.loadScript @ index.js:3802
exports.loadModule @ index.js:4174
setMode @ index.js:10152
push../node_modules/ng2-ace-editor/src/component.js.AceEditorComponent.setMode
I can't understand how to make my application find mode-html.js
. The file is present at location "./node_modules/ace-builds/src-min/mode-html.js
. I have added this path in "script":[]
of package.json
but I still get the error.
"scripts":[
"./node_modules/ace-builds/src-min/ace.js",
"./node_modules/ace-builds/src-min/theme-eclipse.js",
"./node_modules/ace-builds/src-min/mode-html.js"
]
Interestingly, things work if I include ace.js
in the homepage file
<script src="@routes.Assets.versioned("ui/runtime.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/vendor.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/styles.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/main.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("ui/scripts.js")" type="text/javascript"></script>
<script src="@routes.Assets.versioned("javascripts/common/vendor/ace/src-min/ace.js")" type="text/javascript"></script> <!-- this makes things work-->
So I know that issue is that my mode-html.js
file is not getting served and most likely it is the path resolution issue but I can't figure out what is it.
Further analysis shows that the following code in ace.js
causes the error.
exports.loadModule = function(moduleName, onLoad) {
var module, moduleType;
if (Array.isArray(moduleName)) {
moduleType = moduleName[0];
moduleName = moduleName[1];
}
try {
module = require(moduleName);
} catch (e) {}
if (module && !exports.$loading[moduleName])
return onLoad && onLoad(module);
if (!exports.$loading[moduleName])
exports.$loading[moduleName] = [];
exports.$loading[moduleName].push(onLoad);
if (exports.$loading[moduleName].length > 1)
return;
var afterLoad = function() {
require([moduleName], function(module) {
exports._emit("load.module", {name: moduleName, module: module});
var listeners = exports.$loading[moduleName];
exports.$loading[moduleName] = null;
listeners.forEach(function(onLoad) {
onLoad && onLoad(module);
});
});
};
if (!exports.get("packaged"))
return afterLoad();
net.loadScript(exports.moduleUrl(moduleName, moduleType), afterLoad);
reportErrorIfPathIsNotConfigured();
};
var reportErrorIfPathIsNotConfigured = function() {
if (
!options.basePath && !options.workerPath
&& !options.modePath && !options.themePath
&& !Object.keys(options.$moduleUrls).length
) {
console.error(
"Unable to infer path to ace from script src,",
"use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes",
"or with webpack use ace/webpack-resolver"
);
reportErrorIfPathIsNotConfigured = function() {};
}
};
Why does explicitly calling <script src="@routes.Assets.versioned("javascripts/common/vendor/ace/src-min/ace.js")" type="text/javascript"></script>
make the code work. Should this script be already available in ui/scripts.js
as per Angular packaging method https://upgradetoangular.com/angular-news/the-angular-cli-is-a-great-way-to-build-your-angular-app-but-what-it-does-can-be-a-mystery-what-are-those-files-it-generates/?
回答1:
I finally was able to make my code work. My setup is different. I build my Angular application and the it is served from my Play server. The angular build is stored in Play's /public/ui folder. The requests should be in format /assets/ui/.. which gets mapped to /public/ui/... due to a rule in Play routes file
GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
When I ran the code, I got error.
Uncaught DOMException: Failed to execute 'importScripts' on 'WorkerGlobalScope': The script at 'http://localhost:9000/worker-javascript.js' failed to load.
at blob:http://localhost:9000/3df21e42-fecb-4026-8bd6-f2b0d1d0540a:1:1
Earlier, I also got error Unable to infer path to ace from script src, use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes or with webpack use ace/webpack-resolver
It seems ng-ace-editor
imports .js
scripts (theme, mode, worker) based on the theme
and mode
of the editor. The theme
and mode
js
files can be included in scripts.js
but some worker-.js
files can't be (I don't know why, maybe because worker ones are loaded dynamically using importScript.
The scripts section in Angular.json
is (this will all get bundled in scripts.js in Angular's final bundle)
"scripts": [
"./node_modules/ace-builds/src/ace.js",
"./node_modules/ace-builds/src/theme-eclipse.js",
"./node_modules/ace-builds/src/theme-monokai.js",
"./node_modules/ace-builds/src/mode-html.js"
]]
To include worker-.js
files, I added this rule because it seems angular-cli
can't load from node_modules
. So I had to copy the files from node modules
to root of my ui
build - How to include assets from node_modules in angular cli project
"assets": [
"src/assets",
"src/favicon.ico",
{
"glob": "**/*",
"input": "./node_modules/ace-builds/src/",
"output": "/"
}
],
When I executed the code, I found error that http://localhost:9000/worker-javascript.js can't be loaded
. I realised that my files are loaded in /assets/ui/
path and not in the server's root directory. So I set the basepath
to /assets/ui
in the component's .ts
file
import * as ace from 'ace-builds/src-noconflict/ace';
ace.config.set('basePath', '/assets/ui/');
ace.config.set('modePath', '');
ace.config.set('themePath', '');
In summary
basePath
seem to be what is used to load scripts dynamically (eg worker scripts)
modePath
and themePath
are /
as the mode and theme scripts are bundled in scripts.js
and are available at root level
need to copy worker-.js
files outside node_modules
as angular_cli can't copy assets from node_modules
来源:https://stackoverflow.com/questions/60176763/application-cant-find-a-js-file