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/?
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
Related
Installed atom-live-server using atom IDE
Using atom IDE, launching atom-live-server for an html page,
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Classes</title>
</head>
<body>
<script src="code.js"></script>
</body>
</html>
where code.js is,
var Greeter = /** #class */ (function () {
function Greeter(message) {
this.greeting = message;
}
Greeter.prototype.greet = function () {
return "Hello, " + this.greeting;
};
return Greeter;
}());
var greeter = new Greeter("world");
console.log(greeter.greeting);
gives below error in console,
Live reload enabled.
Failed to load resource: `http://127.0.0.1:3000/favicon.ico` the server responded with a status of 404 (Not Found)
Why live-reload server searching for resource favicon.ico?
Just Install "npm install -g live-server" into cmd . then goto your project like cd your project folder name. then run the command "live-server" into cmd. it will automatically open the browser and make your project live reload. No need to atom-live-server or any editor live-reload. Because sometimes atom-live-server doesn't work properly. I personally use it all of my projects. You can try it.
I'm creating HTMLs to inject there revisioned sources from templates as file.html.tpl.
So I have css.html.tpl which has following:
<!-- common:css -->
<!-- endinject -->
<!-- vendor:css -->
<!-- endinject -->
<!-- custom:css -->
<!-- endinject -->
and using this function which read that .html.tpl file Sync, then write in .html the template
exports.createHTMLfromTemplate = function (distDir, templateFileNames) {
for(var i = 0; i < templateFileNames.length; i++) {
var file = templateFileNames[i];
var tplData = fs.readFileSync(path.join(__dirname, file));
var distPath = path.join(distDir, file.slice(0, -4)); // remove .tpl
fs.writeFile(distPath, tplData, function (err) {
if (err) log(exports.error(err));
});
}
};
and then we should have ready .html files with those comments to inject, then we inject our revisioned files.
gulp.task('inject-js', function () {
var distPath = path.join(__dirname, paths.baseSrc)
helper.createHTMLfromTemplate(distPath, 'js.html.tpl')
var injected = gulp.src(distPath + 'js.html');
_.each(jsTasks, function (task) {
var injector = task.filename.substr(0, task.filename.length - 3);
var gulpSrc = gulp.src(task.paths.dest + injector + '*.js', {read: false});
injected
.pipe($gulp.inject(gulpSrc, {name: injector}))
});
return injected
.pipe(gulp.dest(paths.baseSrc))
.on('error', helper.handleError);
});
the result in js.html is following:
<!-- common:css -->
<link rel="stylesheet" href="/static/dist/common-fee68d20.css">
<!-- endinject -->
<!-- vendor:css -->
<link rel="stylesheet" href="/static/dist/vendor-7cd25cb9.css">
<!-- endinject -->
<!-- custom:css -->
<!-- endinject -->
as you can see, if I run this gulp inside of Vagrant (VM), it will not inject in some comments, when running outside Vagrant, e.g. using local gulp, it injects properly.
Why? :)
Full disclosure: I have not used Vagrant
Maybe we can narrow it down. gulp-inject works on the given glob path and:
takes a stream of source files, transforms each file to a string and
injects each transformed string into placeholders in the target stream
files.
If the injection is not taking place, then my first though is that it is not finding the files that it needs to inject.
Try using something like gulp-debug to see if the files that need to be injected actually make it into the pipe stream.
If in the Vagrant environment you are getting the files from source control instead of mapping to the same path as your local dev environment then it should work. Otherwise the vinyl paths may not be resolving to the correct directory.
The puzzling part is that it works, but only partially. If it is not a path issue and you are using reved files then the task responsible for generating the <!-- custom:css --> may be the culprit. That would make more sense.
EDIT
A note from gulp-inject:
Note: As of gulp-inject v4.0.0, NodeJS v4 or above is required. To use
gulp-inject for older versions of Node install a specific version: npm
install gulp-inject#3.
I have no reason to think that this may be the problem, but just in case cross check the Node version number in your local and VM environments.
I have been using Traceur to develop some projects in ES6. In my HTML page, I include local Traceur sources:
<script src="traceur.js"></script>
<script src="bootstrap.js"></script>
and if I have a module in the HTML afterwards like:
<script type="module" src="foo.js"></script>
Then Traceur loads in that module, compiles it and everything works great.
I now want to programmatically add an ES6 module to the page from within another ES6 module (reasons are somewhat complicated). Here was my first attempt:
var module = document.createElement('script');
module.setAttribute('type', 'module');
module.textContent = `
console.log('Inside the module now!');
`;
document.body.appendChild(module);
Unfortunately this doesn't work as Traceur does not monitor the page for every script tag added, I guess.
How can I get Traceur to compile and execute the script? I guess I need to invoke something on either 'traceur' or '$traceurRuntime' but I haven't found a good online source of documentation for that.
You can load other modules using ES6 import statements or TraceurLoader API for dynamic dependencies.
Example from Traceur Documentation
function getLoader() {
var LoaderHooks = traceur.runtime.LoaderHooks;
var loaderHooks = new LoaderHooks(new traceur.util.ErrorReporter(), './');
return new traceur.runtime.TraceurLoader(loaderHooks);
}
getLoader().import('../src/traceur.js',
function(mod) {
console.log('DONE');
},
function(error) {
console.error(error);
}
);
Also, System.js loader seems to be supported as well
window.System = new traceur.runtime.BrowserTraceurLoader();
System.import('./Greeter.js');
Dynamic module loading is a (not-yet-standardized) feature of System:
System.import('./repl-module.js').catch(function(ex) {
console.error('Internal Error ', ex.stack || ex);
});
To make this work you need to npm test then include BrowserSystem
<script src="../bin/BrowserSystem.js"></script>
You might also like to look into https://github.com/systemjs/systemjs as it has great support for browser loading.
BTW the System object may eventually be standardize (perhaps under a different name) in the WHATWG: http://whatwg.github.io/loader/#system-loader-instance
I have a project with ASP.NET 5 and TypeScript. basically this is my wwwroot folder
-wwwroot
|-app
||-person.js
||-employee.js
||-init.js
|-js
||-libraries.js // Contains: systemjs, ...etc
||-app.bundle.js
person.js is an es6 module which exports class Person.
employee.js imports person.js and exports class Employee.
init.js just imports employee.js, creates a new Employee object and console his name.
//init.js
import { Employee } from "./employee";
var p = new Employee();
console.log(p.name);
Now I bundled the three files into app.bundle.js which is located in the js folder using systemjs-builder which produced three named System.register calls:
System.register("wwwroot/app/person.js",...
System.register("wwwroot/app/employee.js",...
System.register("wwwroot/app/init.js"...
In my index.cshtml view file I have these script tags:
<script type="text/javascript" src="./js/libraries.js"></script>
<!-- 2. Configure SystemJS -->
<script type="text/javascript">
System.config({
packages: {
js: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('js/app.bundle')
.then(null, console.error.bind(console));
</script>
apparently since I have named modules, whatever is in the init.js is not being called.
So my question is, how can I call a named System.register call ?
Note: I am new to es6 modules, so this is a test project to get the idea right.
From this wiki page, I solved my problem with this:
<script type="text/javascript">
System.config({
bundles: {
'app.bundle.js': ['wwwroot/app/init']
},
packages: {
wwwroot: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('wwwroot/app/init')
.then(null, console.error.bind(console));
</script>
To explain:
The bundle extension will automatically download a bundle as soon as an attempt to import any module in that bundle is made.
So all I need to do is to tell systemjs to register the init module to my bundle and it will download the bundle and execute whatever is in the init module.
I am trying to use the Async module of https://github.com/millermedeiros/requirejs-plugins to load the googlemap api. My index.html file contains the following requirejs configuration:
<script data-main="scripts/myscript" src="scripts/require.js"></script>
<script>
requirejs.config({
"baseUrl": "scripts",
"paths": {
"async": "require_plugins/async",
"gmaps": "gmaps",
"infobox":"http://google-maps-utility-library-v3.googlecode.com/svn/trunk/infobox/src/infobox",
"jquery":"//code.jquery.com/jquery-2.1.1.min",
"jquery_mob":"//code.jquery.com/mobile/1.4.3/jquery.mobile-1.4.3.min"
},
waitSeconds: 15
});
All my javascript files are stored in a scripts folder (relative to index.html)
e.g. script/myscript.js and script/require.js and the async plugins are stored in a subfolder of script called require_plugins e.g. script/require_plugins/async.js
The javascript where I define the googlemap module is called gmaps.js (stored in the script folder) and looks as follows:
define("GMAP",['async!https://maps.googleapis.com/maps/api/js? &key=xxxxxx®ion=uk&libraries=places,geometry'], function () {
return window.google.maps;
});
I have obfuscated the key parameter intentionally here. According to the documentation, I should be able to use the gmaps module anywhere in other javascript files just by invoking it like so:
require(["gmaps"],function(GMAP)
{
map= new GMAP.Map("#map-div");
//and then some code to display the map
}
Unfortunately, it does not work at all. It seems that the googlemap library has not loaded at all. I use absolute URLs for jquery and that works fine but googlemap fails miserably. My question is: Is there something wrong with my requirejs config? I can't think of anything else causing this fault :(
My understanding is that the name you set in define() is what you need to use when writing the dependencies.
e.g.:
define('GMAP', ['async!<path>'], function() { return window.google.maps; });
require(['GMAP'], function(GMaps) { ... });
This is how I get GMaps to load for me. I have a secondary problem now that other libraries that depend on Maps no longer load.