Hello I playing with javascript and I have the following situation
I have defined a point class. I have defined an edge class which depends on point and a triangle class which depends both on point and edge. How do I ensure that those classes are loaded correctly?
I use them as follows:
<script src="point.js" type="text/javascript"></script>
<script src="edge.js" type="text/javascript"></script>
<script src="triangle.js" type="text/javascript"></script>
<script src="utils.js" type="text/javascript"></script>
the utils.js file are some generic utility functions that uses all of the above classes.
My problem is that I cannot tell the triangle class for example, that the point and edge classes are defined. My code just assumes them to be defined somewhere or else it crashes burning down. Is there a simple #include style mechanism for javascript?
For example I would like to just use the triangle class which internally should somehow find about its dependencies and load them automagically
For example I would like to just use the triangle class which internally should somehow find about its dependencies and load them automagically
You're in luck! Tools like RequireJS exist specifically for this purpose, and do it very well. Take a look at RequireJS's Get Started docs and the many available tutorials. There are other, similar tools like Browserify, but RequireJS is a good place to start and has lots of documentation and users.
Related
A group of volunteers has created a single/multi-select component using StencilJS: https://github.com/NothingAG/adg-components
Now we want to hand it over to the client so they can use it in their project.
My expectation was that the final result could be made available as a single JavaScript file and be included by a website like this:
<script type="module" src="/build/adg-components.esm.js"></script>
<script nomodule src="/build/adg-components.js"></script>
<adg-combobox
id="hobbies"
name="hobbies"
label="Please select your hobbies"
optionslabel="Hobbies"
multi="true"
lang="de"
></adg-combobox>
But it turns out that the command npm run build creates a whole bunch of different files, and all need to be available:
We also included some translation feature, whose files need to be available, too:
My question is: is this just the way it is? Does the client to make all those files available so that the <script type="module" src="/build/adg-components.esm.js"></script> call can find them? Or did we misconfigure the compilation, or forgot about something important?
In a nutshell - yes, that's the way it is. So you need to distribute not just adg-components.esm.js but everything else in the folder as well. The Stencil docs explain this, but to summarize, the purpose is so that components are selectively lazy loaded. If you have a library with 100 components, the browser only needs to download the components that are actually used on the page, not all 100.
I converting a Polymer app to Polymer 2. I'm changing my components to the ES6 Class syntax (yes I know I could leave them in v1.7 hybrid style but I would like them to be ES6 Classes).
However when I transpile the code back to ES5 (with BabelJS) I run into a known issue regarding ES5 'classes' extending native elements (https://github.com/babel/babel/issues/4480).
I tried babel-plugin-transform-custom-element-classes but that didn't work.
So I tried the webcomponents shim meant to fix this issue: https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs
But the shim doesn't work! I don't know what I'm doing wrong :(
<script src="webcomponentsjs/custom-elements-es5-adapter.js"></script>
<script src="webcomponentsjs/webcomponents-lite.js"></script>
...
<y-example></y-example>
...
<script>
/* transpiled to ES5 */
class YExample extends HTMLElement {}
customElements.define('y-example', YExample);
</script>
Here is my jsbin:
http://jsbin.com/feqoniz/edit?html,js,output
Notice I'm including the custom-elements-es5-adapter.js,
also notice the JS panel is using ES6/Babel.
If you remove the custom-elements-es5-adapter.js and change the JS panel to normal Javascript (not ES6/Babel) then everything works fine.
You can include or remove the adapter (leaving ES6/Babel) and the error is basically the same thing, except that when the adapter is included it comes from the adapter code instead: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
I must be doing something silly? Any ideas?
Well, I was doing something silly.. I should have tried upgrading my Babel package.
Upgraded BabelJS from 6.23.1 to latest 6.24.1 and it fixed the problem. :P
I was stucked with the same issue.
The problem was due to my build chain (gulp) transpiling every js files of the project. But the custom-elements-es5-adapter.js file must not be transpiled to work. Transpile everything but this file.
I am having a similar issue and I found a solution that works for me.
Disclaimer: I don't use an app-shell because I have a server-side rendered site with just a few isolated Polymer components on the client-side.
After intense debugging the issue came down to the fact that I was including this block (as suggested on the Polymer guides):
<div id="autogenerated-ce-es5-shim">
<script type="text/javascript">
if (!window.customElements) {
var ceShimContainer = document.querySelector('#autogenerated-ce-es5-shim');
ceShimContainer.parentElement.removeChild(ceShimContainer);
}
</script>
<script type="text/javascript" src="/vendors/webcomponentsjs/custom-elements-es5-adapter.js"></script>
</div>
Because when I ran polymer build it would pick up custom-elements-es5-adapter.js from there.
This is what I did instead:
<script type="text/javascript">
if (window.customElements) {
document.write('<scr' + 'ipt type="text/javascript" src="/vendors/webcomponentsjs/custom-elements-es5-adapter.js"></scr' + 'ipt>');
}
</script>
YES it's not as elegant and quite rustic but, hey, it works! Here I'm tricking the compilers inside polymer build and they won't find this file and hence they won't include it in the build.
I hope it helps!
I'm trying out AMD-way of handling scipts and my choise fell upon requirejs. In this project I use MDL (front-end framework; for those who haven't heard of it think of it as bootstrap 3) which should be included as:
<link rel="stylesheet" href="/bower_components/material-design-lite/material.min.css">
<script src="/bower_components/material-design-lite/material.min.js"></script>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
I am not interested in js API that this framework is providing (if it provides any), I need this script only for UI to work properly when I attach framwerk-specific classes to elements.
According to requirejs philosophy I need only one script file to be included with a script tag on my page - the entry point. I understand that in that main script I need to require dependencies. And if it was say jQuery or underscore i.e. the library I actually require and my code depends on, I would write something like:
require(
['jquery'],
function($) {
$('body').append(...);
}
);
But how do I roll if it's not an actual dependency but I still need it to be loaded in my page and, in this particular case, I need it to be loaded first.
What do I do? My guess is I remove the script tag from my head and specify it in square brackets in my entry point script (as I did for jquery in snippet above) but just don't use it. Is it correct?
But how do I roll if it's not an actual dependency but I still need it to be loaded in my page and, in this particular case, I need it to be loaded first.
RequireJS only guarantees the relative order in which modules are loaded. If a module must absolutely be loaded first, then the chain of dependencies must be such that everything else depends on it, directly or indirectly. RequireJS does not provide a method to say "load this before everything else". You can get this effect only through dependencies. (Sometimes people think the deps configuration option guarantees that some modules will load first. It does not. Or they think that the order of dependencies in a require or define call sets an order for loading beyond what the dependencies set. It does not. If A and B have no dependencies of their own then require(['A', 'B'], ... and require['B', 'A'], ... are both free to load the modules in any order.)
What do I do? My guess is I remove the script tag from my head and specify it in square brackets in my entry point script (as I did for jquery in snippet above) but just don't use it. Is it correct?
In theory there's no problem with doing this. I say "in theory" because I do not use MDL so I don't know if MDL has any need that would prevent it from working. You've compared MDL with Bootstrap 3. What you describe is how I load Bootstrap with RequireJS. I tend to use the CommonJS idiom so modules that need Bootstrap look something like this:
define(function (require, exports, module) {
'use strict';
require("bootstrap");
There's no need to do something like var bootstrap = require("bootstrap"); because the value would be undefined anyway because the JS code of Bootstrap installs itself as jQuery plugins.
I'm trying to throw together a single js file that includes the functionality of jquery's .load(), as well as the methods, in an effort to link only to a single js file, rather than both jquery and the load methods.
Instead of
<script src="jquery.min.js" type="text/javascript"></script>
<script src="load.js" type="text/javascript"></script>
this
<script src="load_including-necessary-js-for-load-methods.js" type="text/javascript"></script>
So basically I'm trying to extract only the necessary code from within jquery that makes .load() work and include it in the file with the load methods.
Suggest, instead, that you use something along the lines of html5boilerplate's jQuery call:
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.8.2.min.js"><\/script>')</script>
Accessing it via the CDN ensures high-speed delivery of the jQuery code that is used by thousands of other pages/users on a constant basis,
... which also means that that code is most likely cached in your users' browsers ...
... which equates to highly-tested code that you're really not "paying for" in terms of overall load time. The second line, of course, allows you to offer a copy of it from your own site, in case the CDN has a hiccup, or you need to be testing offline (in which case, AJAX is borked for you any way you look at it, anyhow...).
OTHERWISE, check out the instructions on jQuery's Github: https://github.com/jquery/jquery#how-to-build-your-own-jquery and read up on building your own... they have instructions, there for excluding modules that you don't want from the library.
After that, you'll probably want to use some kind of bundling script to bundle all your JS (your custom jQuery build + your scripts) together, if you want to reduce everything to one call.
i don't know your reason why you cannot use all jquery library, but you still can write own js script and use onload or document.load, window.load its you reduce your code. If you need jQuery load() ... read and try to first comment of your question or use all small(own) jQuery library than waste of your time with this.
I am currently maintaining a large number of JS files and the dependency issue is growing over my head. Right now I have each function in a separate file and I manually maintain a database to work out the dependencies between functions.
This I would like to automate. For instance if I have the function f
Array.prototype.f = function() {};
which is referenced in another function g
MyObject.g = function() {
var a = new Array();
a.f();
};
I want to be able to detect that g is referencing f.
How do I go about this? Where do I start? Do I need to actually write a compiler or can I tweak Spidermonkey for instance? Did anyone else already do this?
Any pointers to get me started is very much appreciated
Thanks
Dok
Whilst you could theoretically write a static analysis tool that detected use of globals defined in other files, such as use of MyObject, you couldn't realistically track usage of prototype extension methods.
JavaScript is a dynamically-typed language so there's no practical way for any tool to know that a, if passed out of the g function, is an Array, and so if f() is called on it there's a dependency. It only gets determined what variables hold what types at run-time, so to find out you'd need an interpreter and you've made yourself a Turing-complete problem.
Not to mention the other dynamic aspects of JavaScript that completely defy static analysis, such as fetching properties by square bracket notation, the dreaded eval, or strings in timeouts or event handler attributes.
I think it's a bit of a non-starter really. You're probably better of tracking dependencies manually, but simplifying it by grouping related functions into modules which will be your basic unit of dependency tracking. OK, you'll pull in a few more functions that you technically need, but hopefully not too much.
It's also a good idea to namespace each module, so it's very clear where each call is going, making it easy to keep the dependencies in control manually (eg. by a // uses: ThisModule, ThatModule comment at the top).
Since extensions of the built-in prototypes are trickier to keep track of, keep them down to a bare minimum. Extending eg. Array to include the ECMAScript Fifth Edition methods (like indexOf) on browsers that don't already have them is a good thing to do as a basic fixup that all scripts will use. Adding completely new arbitrary functionality to existing prototypes is questionable.
Have you tried using a dependency manager like RequireJS or LabJS? I noticed no one's mentioned them in this thread.
From http://requirejs.org/docs/start.html:
Inside of main.js, you can use require() to load any other scripts you
need to run:
require(["helper/util"], function(util) {
//This function is called when scripts/helper/util.js is loaded.
//If util.js calls define(), then this function is not fired until
//util's dependencies have loaded, and the util argument will hold
//the module value for "helper/util".
});
You can nest those dependencies as well, so helper/util can require some other files within itself.
As #bobince already suggested, doing static analysis on a JavaScript program is a close to impossible problem to crack. Google Closure compiler does it to some extent but then it also relies on external help from JSDoc comments.
I had a similar problem of finding the order in which JS files should be concatenated in a previous project, and since there were loads of JS files, manually updating the inclusion order seemed too tedious. Instead, I stuck with certain conventions of what constitutes a dependency for my purposes, and based upon that and using simple regexp :) I was able to generated the correct inclusion order.
The solution used a topological sort algorithm to generate a dependency graph which then listed the files in the order in which they should be included to satisfy all dependencies. Since each file was basically a pseudo-class using MooTools syntax, there were only 3 ways dependencies could be created for my situation.
When a class Extended some other class.
When a class Implemented some other class.
When a class instantiated an object of some other class using the new keyword.
It was a simple, and definitely a broken solution for general purpose usage but it served me well. If you're interested in the solution, you can see the code here - it's in Ruby.
If your dependencies are more complex, then perhaps you could manually list the dependencies in each JS file itself using comments and some homegrown syntax such as:
// requires: Array
// requires: view/TabPanel
// requires: view/TabBar
Then read each JS file, parse out the requires comments, and construct a dependency graph which will give you the inclusion order you need.
It would be nice to have a tool that can automatically detect those dependencies for you and choose how they are loaded. The best solutions today are a bit cruder though. I created a dependency manager for my particular needs that I want to add to the list (Pyramid Dependency Manager). It has some key features which solve some unique use cases.
Handles other files (including inserting html for views...yes, you can separate your views during development)
Combines the files for you in javascript when you are ready for release (no need to install external tools)
Has a generic include for all html pages. You only have to update one file when a dependency gets added, removed, renamed, etc
Some sample code to show how it works during development.
File: dependencyLoader.js
//Set up file dependencies
Pyramid.newDependency({
name: 'standard',
files: [
'standardResources/jquery.1.6.1.min.js'
]
});
Pyramid.newDependency({
name:'lookAndFeel',
files: [
'styles.css',
'customStyles.css',
'applyStyles.js'
]
});
Pyramid.newDependency({
name:'main',
files: [
'createNamespace.js',
'views/buttonView.view', //contains just html code for a jquery.tmpl template
'models/person.js',
'init.js'
],
dependencies: ['standard','lookAndFeel']
});
Html Files
<head>
<script src="standardResources/pyramid-1.0.1.js"></script>
<script src="dependencyLoader.js"></script>
<script type="text/javascript">
Pyramid.load('main');
</script>
</head>
It does require you to maintain a single file to manage dependencies. I am thinking about creating a program that can automatically generate the loader file for you based on includes in the header but since it handles many different types of dependencies, maintaining them in one file might actually be better.
JSAnalyse uses static code analysis to detect dependencies between javascript files:
http://jsanalyse.codeplex.com/
It also allows you to define the allowed dependencies and to ensure it during the build, for instance. Of course, it cannot detect all dependencies because javascript is dynamic interpretet language which is not type-safe, like already mentioned. But it at least makes you aware of your javascript dependency graph and helps you to keep it under control.
I have written a tool to do something like this: http://github.com/damonsmith/js-class-loader
It's most useful if you have a java webapp and you structure your JS code in the java style. If you do that, it can detect all of your code dependencies and bundle them up, with support for both runtime and parse-time dependencies.