Error using crossroads.js in optimized (r.js) require setup - javascript

I have developed an application using RequireJS, with no optimization layer - Require downloads each file separately. Here is the outer markup:
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
var require = {
//some basic config
};
</script>
</head>
<body>
<!--snip-->
</body>
<script type="text/javascript" data-main="main" src="scripts/lib/require.min.js"></script>
</html>
This functions without any issue, but with 100+ files the load time is really getting up there. So, time to introduce r.js optimization! I use node and r.js to create a combined file, and change data-main="main" to data-main="_build/main".
I get the following error:
Error: Mismatched anonymous define() module: (the entire body of crossroads.js)
Thoughts:
There are no manual / out-of-band define() calls or anonymous modules. Everything goes through the optimizer into this one file.
This isn't even our file - it's crossroads.min.js, which Require is able to handle just fine when the optimizer isn't involved.
I am still digging, but hoping someone can save me some time here.

TL;DR; Use the unminified version of crossroads.js, since you are doing a r.js build it will already compress the source file.
crossroads uses an unnamed define and is wrapped into a custom UMD (universal module definition). The minified version won't work well since r.js can't add the proper module name.
before minification:
(function(define){define(["signals"], ...
after minification:
(function(a){a(["signals"], ...
r.js can't figure out what a means, it only looks for define calls.

Related

why are dev servers required for web based front end bundlers

I never really thought about it until I switched from webpack to brunch where I saw the following lines in index.html:
<script type="text/javascript">
require('main');
</script>
When you try to simply open up a local html page (even after everything's been built in webpack), it produces errors (SCRIPT5009: SCRIPT5009: 'require' is not defined) and doesn't render correctly, but when you open the page through a dev server it renders correctly.
Why are dev servers required for bundlers? What are the dev servers doing behind the scenes to allow the browser to properly render pages with bundles? Isn't the rendering capability built into the browser itself?
Originally I thought it was putting up a node server to help translate commands such as require(), but the above shows that the line was passed through to the browser. Why does the browser choke on that command when you just open the html file versus when it's delivered via a server?
On a side note everything works fine when the page is delivered via apache as well. If it is some sort of node translation, then how does apache not choke on it?
edit:
The files that show delivered are:
logo.png (just a vue logo)
app.js (the bundled javascript file)
the html file, which looks like:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-webpack-brunch</title>
</head>
<body>
<div id="app"></div>
<script src="/app.js"></script>
<script type="text/javascript">
require('main');
</script>
</body>
</html>
Everything is delivered exactly like that, and that's the extent of the project. If the javascript bundle were including requirejs then it should also work if you just open the file locally as well
Edit 2:
typing require in the console produces the following:
(t,r){null==r&&(r="/");var i=l(t);if(o.call(n,i))return n[i].exports;if(o.call(e,i))return u(i,e[i]);throw new Error("Cannot find module '"+t+"' from '"+r+"'")}:
<script src="/app.js"></script>
You are loading /app.js which will define your require function.
The URL starts with a /.
If you load it from a webserver, the / refers to the root of the site.
If you load it from your local file system, then the / refers to the root of your filesystem (or disk if you are Windows). This will be the wrong place because webpack will not generate it there (you would not want c:\app.js created for every application you built with webpack).
The require keyword is giving errors because it's a made up way to require external files. If you used import, the standard native implementation, it would work out of the box on newer browsers. Bundlers aren't required.
Require came from https://requirejs.org/
They're looking for that word require and, essentially, injecting code at that source path into a built file. It'd be like if I made a injectFile keyword for my InjectFileJS project.
<script type="text/javascript">
injectFile('main');
</script>
That would produce the same error, injectFile is undefined. You would need to run my made up file loader on your web server to parse and transpile the files for that function to exist.
However, if you use import you can get away with not having a bundler as a requirement on new browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import

NW.js + Babel: ES6 import working but not export?

I'm building a NW.js app, currently with babel-standalone and React. I can use ES6 import, but ES6 export on the other hand does not work, console spits out unexpected token export. What's going on?
index.html:
<html>
<head>
<meta charset="utf-8">
<script src="assets/react.min.js" charset="utf-8"></script>
<script src="assets/react-dom.min.js" charset="utf-8"></script>
<script src="assets/babel.min.js" charset="utf-8"></script>
</head>
<body>
<script type="text/babel" src="script/App.js"></script>
</body>
</html>
(yes, Babel indeed works, since React stuff inside runs OK)
In app.js:
import Lib from "./script/lib.js";
(and it's indeed exporting lib.js correctly, since that is the file responsible for the error)
In script/lib.js:
export default class {...};
I'm aware I can use Node modules instead, or even HTML script loading, but that's beside the point. I want to know why export doesn't work even if Babel doesn't seem to be broken, and even import works fine.
The problem is that Babel doesn't see files that were loaded via require, and they are loaded as they are, without transpilation.
There can be several ways to work this around, but the easiest one will be using Babel at build step.
Process your source code and then load processed code nw.js environment. The example how to do that you can find at this boilerplate project

Aurelia Project Setup has error out of the box, what's the fix?

I have followed the simple step-by-step instructions in the Basic Aurelia Project Setup guide. But starting the index.html in a browser results in the config-esnext.js file throwing: "JavaScript runtime error: 'System' is undefined". This is on the first line: System.config({...
The browser's output window has this to say:
"Could not find file 'C:\Users\Bruce\Dropbox\Projects Aurelia\Basic Aurelia Setup\scripts\system.js.map'..Unhandled exception at line 1, column 1 in http://localhost:56477/scripts/config-esnext.js"
Is there some "map" configuration missing from the simple instructions? I am running the project from Visual Studio 2015, configured for Esnext.
The comments to the original question have some good discussion going. But for the sake of providing an "answer" for others to find, here goes.
Without seeing your index.html file, I can't determine exactly what is going on. But the error you're seeing is happening because System isn't defined on the window. This will happen if you haven't loaded up System yet. You need to make sure that your index.html file loads up SystemJS first, then you load up your config file.
You can see in the skeleton project's index.html found here, that system.js is loaded before we bring in the configuration file. Here is an example of a proper index.html using SystemJS.
<!DOCTYPE html>
<html>
<head>
<title>Aurelia</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body aurelia-app="main">
<span>Loading...</span>
<script src="jspm_packages/system.js"></script>
<script src="config.js"></script>
<script>
System.import('aurelia-bootstrapper');
</script>
</body>
</html>
As an alternative, the CLI helps get a skeleton project up quickly (it doesn't include a navigation example, it is a bare-bones skeleton). It uses RequireJS however, but we have plans to support other module loaders (such as SystemJS) down the road.

Initialising requirejs app in both optimised and non-optimised build

I'm confused about my r.js optimised script. I imagine the answer to my question is in the documentation but I think I'm going doc-blind from staring at it too long.
My application has a directory structure like this
-index.htm
-js/app.js
-js/init.js
-js/appname/*.js
When in non-optimised mode index.htm contains the following line:
<script type="text/javascript" data-main="js/app" src="js/lib/require-2.1.11.js"></script>
and everything works fine. My abridged js/app.js script looks like this:
requirejs.config({
baseUrl: 'js',
paths: {
...
}
});
require(['init']);
When I build the optimised script I specify js/app.js as the mainConfigFile and everything builds as expected. However when I update my script tag's data-main attribute to the build product my application doesn't initialise.
If I manually execute require(['init']) in the console it starts up as expected. Because r.js is using js/app.js as its config file that doesn't get included in the optimised script, which means my require(['init']) also doesn't get included.
I thought I could fix this by moving require(['init']) to the end of js/init.js and this does fix the optimised build (it initialised as expected), but now that the call isn't in js/app.js the non-optimised version never initialises. If I include the call in both files I get an error.
How can I ensure my first module is required after either the optimised or non-optimised file(s) are loaded? I don't understand how I'm supposed to make that first call after my first module's dependencies have fully loaded.
Because r.js is using js/app.js as its config file that doesn't get included in the optimised script
Well, then modify the build config you pass to r.js so that js/app.js is included in the final optimized bundle. There's nothing that forbids you from including the file you point to with mainConfigFile in the final bundle.

Javascript requirejs in development but compiled in production

I'm beginning to evaluate javascript module tools like RequireJS for javascript modularization. This seems useful, especially during development, so I don't need to recompile all of the js files into mylib-<version>.js whenever I change one of the dependent files.
My app is distributed with both html and javascript files, and in production, I would like to use the compiled version of the javascript file.
So in development, my html file might look something like
<html>
<head>
<script data-main="scripts/main" src="scripts/require.js"></script>
</head>
</html>
But in production, I would expect it to look more like
<html>
<head>
<script src="mylib-1.0.js"></script>
</head>
</html>
I wouldn't think it production that there should be any need to reference requirejs if I am distributing a compiled file.
Is there a way to do this without having to manually change my html files before I distribute the app?
RequireJs has an optimization tool, which can help you to minify and concatenate your modules. It has a lot of options, and can be difficult to use, but it gets easier with a build tool like GruntJs or (especially) Yeoman, which uses GruntJs to build.
In both you can use the rjs task (which optimizes modules), but again Yeoman is a bit easier since it has generators which will configure it already for you:
// usemin handler should point to the file containing
// the usemin blocks to be parsed
'usemin-handler': {
html: 'index.html'
},
// rjs configuration. You don't necessarily need to specify the typical
// `path` configuration, the rjs task will parse these values from your
// main module, using http://requirejs.org/docs/optimization.html#mainConfigFile
//
// name / out / mainConfig file should be used. You can let it blank if
// you're using usemin-handler to parse rjs config from markup (default
// setup)
rjs: {
// no minification, is done by the min task
optimize: 'none',
baseUrl: './scripts',
wrap: true,
name: 'main'
},
In the index.html you just use a comment line to specify which js files should be minified/concatenated to which output file:
<!-- build:js scripts/amd-app.js -->
<script data-main="scripts/main" src="scripts/vendor/require.js"></script>
<!-- endbuild -->
In the example above, the modules will be concatenated to ONE file, named amd-app.js.
Edit:
This will be done by executing grunt from the command line. This will start a lot of useful tasks, which will build the project in a dist folder, but again this is highly adaptable.
The resulting index.html file (in dist) has only (if you want) one javascript file:
<script src="scripts/15964141.amd-app.js"></script>
My advice: use Yeoman to make life easier (at least for handling minification/concatenation).
First you have to compile your depency tree into one file using the r compiler. After that you can a striped down AMD loader like almond. At least you have to find a way to change the url in your index html.
Take a look at gruntjs which can automatize the whole thing, there a bunch task to like usemin that helps you with the process.

Categories