In requirejs it is possible to define an anonymous module or to give it a string id. According to this article, you would normally not use the string id:
You would not normally use the id when you define your module. It is typically used by tools when optimizing a RequireJS application.
I currently define my modules anonymously and use require.config.paths for the mappings. What I don't understand is: why does requirejs allow you to specify string id's if they're not needed?
why does requirejs allow you to specify string id's if they're not needed?
They only are not needed if require can figure out what module it is that just called define. This is the standard when require() did load the script file that contains the module, whose name and path it knows.
However, the optimizer will put multiple modules in a single file, and there needs to be a different way to figure out what modules are define()d. From the docs:
These [names] are normally generated by the optimization tool. You can
explicitly name modules yourself, but it makes the modules less
portable -- if you move the file to another directory you will need to
change the name. It is normally best to avoid coding in a name for the
module and just let the optimization tool burn in the module names.
The optimization tool needs to add the names so that more than one
module can be bundled in a file, to allow for faster loading in the
browser.
I can't answer as to James Burke's motivations, but I can point out instances of its usefulness.
Define your own single page "layer" for testing, using JSBin or JSFiddle. The following code can be easily executed without having to stand up endpoints for each module or to use r.js to create a layer.
define('A',[], function(){ console.log('A loaded');});
define('B',[], function(){ console.log('B loaded');});
define('c',['A','B'], function(){ console.log('C loaded');});
Define a "local override" for troubleshooting. Add a define right before your require to easily preempt a module definition add a new module so you don't have to touch several files while you're working
define('plugin/fancySelect',[], function(){/* ... */});
require([ /* ... */], function(){
// your main application code
});
Related
While trying to get started with Reason, in one JavaScript project, I've got an extremely light file that tries to be a Reason-typed interface to the existing, heavy, library:
/* TheLibrary.re */
type engine
external addEngine : string -> engine -> unit = "" [##bs.val] [##bs.module "../"]
However, when I try to use that library in a ReasonReact project (having added #org/the-library to the bsconfig.json bs-dependencies),
/* AComponent.re */
[#bs.val] [#bs.module "#org/game-engine/dist/game-engine.js"]
external gameEngine : TheLibrary.engine = "default";
/* Further down, a React lifecycle method, */
TheLibrary.addEngine("Game", gameEngine);
I get errors about ../ being not found, relative to that React component:
./src/components/main-menu/AComponent.re
Module not found: Can't resolve '../' in '/Users/ec/Work/reason-reacty/src/components/main-menu'
I've also tried, instead of ../ in TheLibrary.re's external declaration:
#bs.module "./index.js" (the direct, ES6 entry-point for the untyped-JavaScript side of the package in question,)
#bs.module "#org/the-library", the entire name of said library (even though I'm typing inside that library???)
Please help! I'd love to be able to further adopt ML, but I'm having the hardest time wrapping my head around ReasonReact's dependency-resolution!
Additional context:
So, we're trying to build our first ReasonReact project, and we've successfully added baby's-first-opaque-types to one of our internal libraries and include that in the ReasonReact page with something like the following — which works, by the way:
/* Imports.re */
type engine;
[#bs.val] [#bs.module "#org/game-engine/dist/game-engine.js"]
external gameEngine : engine = "default";
[#bs.val] [#bs.module "#org/the-library"] [#bs.scope "default"]
external addEngine : (string, engine) => unit = "";
This yields, when we Imports.(addEngine("Game", gameEngine)), the global setup line we need: TheLibrary.addEngine("Game", GameEngine). I'm in the very first stages of trying to upstream that typing-information into the parent project, and publish that code to npm, so that all consuming projects can start to use Reason.
t sounds like you might be a bit confused about the different tools that make up your toolchain, so let's first go through them one by one to put them in their place:
ReasonReact is a library of opinionated, "thick" bindings to react.js, which despite the name isn't actually all that Reason-specific, except for its integration with Reason's JSX syntax. It would be more accurate to call it a BuckleScript library.
Reason is mostly just the syntax you use, but is often also used more broadly to refer to the ecosystem around it, and usually also imply that BuckleScript is being used.
OCaml is the underlying language. The "semantics" of Reason, if you will.
BuckleScript is the OCaml-to-JavaScript compiler. It compiles ONE source file, which is considered a module, into ONE JavaScript module, but also requires the type information of other OCaml modules as input.
Now, I suspect you already know most of that, but what you do not seem to know is that NONE of these actually do ANY dependency resolution. These next parts of your toolchain are what does that:
The BuckleScript Build System, or bsb, is what finds all the modules in your local project according to what you've specified in src and any BuckleScript libraries you've listed in bs-dependecies in bsconfig.json. It will figure out the dependency order of all these and feed them to the compiler in the correct order to produce one JavaScript module for each OCaml module (along with some other artefacts containing type information and such). But it will not resolve any JavaScript dependencies.
Lastly, webpack, or some other JavaScript bundler, is what you likely use to combine all the JavaScript modules into a single file, and which therefore needs to resolve any JavaScript dependencies. And this is likely where the error message comes from.
Using [#bs.module "some-module"] will make the BuckleScript compiler emit var ... = require('some-module') (or import ... from 'some-module' if es6 is used), but BuckleScript itself will not do anything more with it. The string you pass to #bs.module is the same string you would pass to require if it had been an ordinary CommonJS module (or whatever other module format you have configured).
Also note that the import is not emitted where the external is defined, but where it's used. You can work around, or "ground" it in a module by re-exporting it as an ordinary definition, ie. let addEngine = addEngine.
In order to precisely answer your question I would need to know which bundler you use, where you've configured BuckleScript to output its JavaScript artefacts, where the externals are used, not just defined, and where the external JavaScript module is located. But I hope all this underlying knowledge will make it easy for you and future readers to identify and resolve the problem yourself. If you're still a bit unsure, look at the compiled JavaScript artefacts and just treat them as ordinary JavaScript modules. At this point that's really all they are.
I followed the documentation to put the constants in the lib/constants.js file.
Question:
How to access these constants in my client side html and js files?
Variables in Meteor are file-scoped.
Normally a var myVar would go in the global Node context, however in Meteor it stays enclosed in the file (which makes it really useful to write more transparent code). What happens is that Meteor will wrap all files in an IIFE, scoping the variables in that function and thus effectively in the file.
To define a global variable, simply remove the var/let/const keyword and Meteor will take care to export it. You have to create functions through the same mechanism (myFunc = function myFunc() {} or myFunc = () => {}). This export will either be client-side if the code is in the client directory, or server-side if it is in the server directory, or both if it is in some other not-so-special directories.
Don't forget to follow these rules:
HTML template files are always loaded before everything else
Files beginning with main. are loaded last
Files inside any lib/ directory are loaded next
Files with deeper paths are loaded next
Files are then loaded in alphabetical order of the entire path
Now you may run into an issue server-side if you try to access this global variable immediately, but Meteor hasn't yet instantiated it because it hasn't run over the file defining the variable. So you have to fight with files and folder names, or maybe try to trick Meteor.startup() (good luck with that). This means less readable, fragile location-dependant code. One of your colleague moves a file and your application breaks.
Or maybe you just don't want to have to go back to the documentation each time you add a file to run a five-step process to know where to place this file and how to name it.
There is two solutions to this problem as of Meteor 1.3:
1. ES6 modules
Meteor 1.3 (currently in beta) allows you to use modules in your application by using the modules package (meteor add modules or api.use('modules')).
Modules go a long way, here is a simple example taken directly from the link above:
File: a.js (loaded first with traditional load order rules):
import {bThing} from './b.js';
// bThing is now usable here
File: b.js (loaded second with traditional load order rules):
export const bThing = 'my constant';
Meteor 1.3 will take care of loading the b.js file before a.js since it's been explicitly told so.
2. Packages
The last option to declare global variables is to create a package.
meteor create --package global_constants
Each variable declared without the var keyword is exported to the whole package. It means that you can create your variables in their own files, finely grain the load order with api.addFiles, control if they should go to the client, the server, or both. It also allows you to api.use these variables in other packages.
This means clear, reusable code. Do you want to add a constant? Either do it in one of the already created file or create one and api.addFiles it.
You can read more about package management in the doc.
Here's a quote from "Structuring your application":
This [using packages] is the ultimate in code separation, modularity, and reusability. If you put the code for each feature in a separate package, the code for one feature won't be able to access the code for the other feature except through exports, making every dependency explicit. This also allows for the easiest independent testing of features. You can also publish the packages and use them in multiple apps with meteor add.
It's amazing to combine the two approaches with Meteor 1.3. Modules are way easier and lighter to write than packages since using them is one export line and as many imports as needed rather than the whole package creation procedure, but not as dumb-error-proof (forgot to write the import line at top of file) as packages.
A good bet would be to use modules first, then switch to a package as soon as they're tiring to write or if an error happened because of it (miswritten the import, ...).
Just make sure to avoid relying on traditional load order if you're doing anything bigger than a POC.
You will need to make them global variables in order for other files to see them.
JavaScript
/lib/constants.js
THE_ANSWER = 42; // note the lack of var
/client/some-other-file.js
console.log(THE_ANSWER);
CoffeeScript
/lib/constants.coffee
#THE_ANSWER = 42
/client/some-other-file.coffee
console.log THE_ANSWER
I'm trying to update the javascript on a large scale, php/codeigniter based website. It has many, many php partials for code being loaded onto certain pages, but only one footer, header. Most of the partials have inline script tags in them for loading javascript. This needs to be fixed and because the site is very modular with components being used multiple times across pages, require.js seems like a pretty good solution.
So, it's instantiate javascript, we typically do this.
<script type="javascript" src="../js/scriptname.js">
<script type="javascript">
DP.scriptname.init(parameters)
</script>
I'd like to get away from this and just have a have a single entry point for the js using require.
My question is this: what's the best way to instantiate javascript for certain pages using require? Do I need I need to continue including my scripts in the partial and then do something like writing a require module for that specific page and then wrap it all in my data-main script like this? We're planning on using Backbone and Marionette as well, but I won't be able to use the Backbone router to do anything like setting hash URLs. Should I use the URLs to instantiate my require modules perhaps?
Ok, hope someone can help. My experience has typically been in building single page websites. This is different. Thanks
Cam
Well, if I understand your question correctly, you can use Require JS in such way.
First of all, write a config in which you can describe mapping between module names and concrete files. For example:
requirejs.config({
baseUrl: 'js/modules' // by default load any module using this path
});
After that you should refactor your existing module and adjust it to the AMD format (see http://requirejs.org/docs/whyamd.html)
As a result of this step you will have something like this (let's say in file 'js/modules/scriptname.js'):
// module has the same name as the file, which contains it - "scriptname"
define(function () {
// define the module value by returning a value
return function () {};
});
And as a final step you can refactor your inline script and use this module in such way:
<script type="javascript">
// when we place name of the module as a first argument of the "define"
// function, Require JS find file that contains it and load it asynchronously
define(["scriptname"], function (scriptname) {
// "scriptname" now contains value that we recieve from the module definition
scriptname.init(parameters);
});
</script>
Hope this helps.
Note. My solution based on this section of official Require JS documentation: http://requirejs.org/docs/api.html#jsfiles
This question seems to come up a lot, so I'll point you to some resources that may help:
How does RequireJS work with multiple pages and partial views? - https://stackoverflow.com/a/10816983/617615
Modular HTML components with RequireJS - http://simonsmith.io/modular-html-components-with-requirejs/
Example RequireJS-based project that has multiple pages that share a common set of modules - https://github.com/requirejs/example-multipage
I'm working with a very large project that uses:
Legacy JSP pages that includes javascript files with script tags
Backbone models and views that uses other javascript modules without RequireJS
We now want to start using RequireJS with jQuery, BackboneJS and UnderscoreJS for everything we develop from now on, but we don't have the resources to rewrite all the legacy JSP pages. We may have time to rewrite the Backbone models and views we have already developed.
The problem is that for our legacy code (both 1 and 2 above) we include all our javascript files in a huge file and ship to the browsers. This huge file must be able to co-exist with our new RequireJS templates, but how can I e.g. separate certain parts of the huge file, so I can use them with the templates using RequireJS? Without having to rewrite all pages that uses this part of the file, or having duplicate code.
Thanks!
I don't know if I fully grasp the problem at hand, but I think a the shim or map functions of RequireJS will help you out.
Extract the parts you want in a new module from your huge javascript file. Then tell RequireJS that your huge javascript file is a dependecy for this new module using shim. Something like:
requirejs.config({
shim: {
'new-module': {
deps: ['huge-javascript-file'],
exports: 'NewModule'
}
});
Shim documentation: http://requirejs.org/docs/api.html#config-shim
The map function might be useful when only portions of your new code have to use your old huge file. Check out this documentation: http://requirejs.org/docs/api.html#config-map
I don't think there is One True Way to achieve this, but I've approached a similar problem by defining module "facades" around the globally scoped code. Let's say your legacy scripts define a global variable called foo. You can define a AMD module and export that variable from it:
//foo.js
define(function() {
return window.foo;
});
//bar.js
define(['foo'], function(foo) {
//do something with foo
});
This way you only need to write a single-line facade every time you need to use a new piece of the existing, globally defined code, without breaking existing code which expects the same code to be globally defined. Over time you can move and refactor the actual implementation into the module without breaking consumer code.
I'm new to Dojo so I don't quite understand all of Dojo's features. Here are some questions, but I'm sure some of them seem really stupid since I don't quite get how Dojo is structured yet:
How do you create multiple modules within a single js file and access the module in the file it's created? Also, how do you access specific modules from a file containing multiple modules?
What is the difference between require and define?
I successfully required a module from a file, but I can't figure out how to get the variables out of the file, how do you do this?
I was looking at how Dojo required its modules and notice that it does a http request for each file, but isn't that really inefficient when you're dealing with lots of modules and/or on a large site, you really would like to minimize the number of http requests necessary? What's the way around this?
Reading through The Dojo Loader will provide answers.
Basically module = file and very often (as a matter of best practice) module = file = class (more precisely public class defined via dojo/_base/declare).
Ad #4: You will need to employ The Dojo Build System, that will resolve all the dependencies and put all your modules into a single file (or more files, this depends on your build profile). Have a look at Dojo Boilerplate project, it may help with building your application.
How do you create multiple modules within a single js file?
While this is possible to do, and is done by the build system when it creates layer files, it is not recommended. Putting multiple modules in a single file means you have to use a different form of define that gives an explicit ID to eahc of them. This is less flexible then having the module IDs automatically derived from the file name and path (this, together with relative paths makes it much easier to move and rename AMD modules, compared to old-style modules)
What is the difference between require and define?
define is a beefed up version of require that defines a new module with its return value.
I successfully required a module from a file, but I can't figure out how to get the variables out of the file.
I am not sure wha toyu mean with this (without giving a concrete runnable example) but all you have to do is create an object to be the value of your module and return it from define. This is not very far off from how you would define modules the old way, with manual "namespaces"
//foo.js
define([], function(){
var M = {}; //the exported stuff will go here
var myVariable = 16; //private function variables are private (like they are everywhere else)
//and cannot be seen from the outside
M.anumber = myvariable + 1; //things on the returned object can be seen from the outside
return M; //people who require this module will get this return value
});
//bar.js
define(['foo'], function(foo){
console.log( foo.anumber );
});
I was looking at how Dojo required its modules and notice that it does a http request for each file...
As phusick pointed out, the build system can be used to bundle all the modules into a single file (giving you the best of both worlds - modularity during development and performance during deployment). It can also do other cool stuff, like bundling CSS and passing the Javascript through a minifier or through the Closure compiler, checking ifdef for creating platform-dependent builds, etc.