I have a multi-page / mulit-application minifcation I'm trying to make work.
the structure is as follows
common/
--main config file that defines the common libs
common/build
--app.build.js (see example below)
application1/
--application
--milion other files
application2/
--application
--thousand other files
this is placed in the header the page(s)
</style><script data-main='common/main' src='libraries/require.js'></script>
footer like this
<script>require(['../application1/application']);</script>
<script>require(['../application2/application']);</script>
This approach works perfect when using a bunch of files, and the applications run and interact perfect
However trying to make them into one seems a bit more of a challenge in terms of making it work.Granted I could just be an idiot
Build File
({
baseUrl: "../",
mainConfigFile: '../main.js',
optimize: 'uglify',
optimizeCss: 'standard',
out: "../global.min.js",
//insertRequire: ['main'],
include: ['../application1/application', '../application2/application'],
wrap: true // have tried both options - this makes the scenario at the bottom work
})
This works perfect and produces a lovely global.min.js. Challenge is it does not execute the callbacks on define calls I include it like so:
this is placed in the header the page(s)
</style><script data-main='common/main' src='libraries/require.js'></script>
footer like this
<script>require(['../common/global.min']);</script>
HOWEVER: if I keep the old requires in places like so:
<script>require(['../application1/application']);</script>
<script>require(['../application2/application']);</script>
it downloads 3 files
common/global.min.js
application1/application.js
application2/application.js
NOTE: At this point it is missing about 150 files, but the application(s) work perfect.
Having spent some serious time on this, my head is now properly wrecked and I can't figure out how to make it work from a single minified file.
Any help much appreciated as I have tried whatever I could think of. Happy to share all the files, howvere there is a lot of them ;-)
This is an educated guess, based on what you've shown in the question and experience with RequireJS' failure modes. I'm guessing "./common/global.min" is not a module name. (If you want to check this, open your optimized bundle and look at all the define calls. If you find that none of them has "./common/global.min", then it is not a module name.)
When you require "./common/global.min", RequireJS loads the corresponding file, and then looks in it for a module named "./common/global.min". It finds none, and your code does not get to run.
One way to fix this is to use a RequireJS configuration with your optimized bundle that maps names like this:
paths: {
'../application1/application': './common/global.min'
'../application2/application': './common/global.min'
}
And call require with these module names instead of "./common/global.min". This configuration tells RequireJS "when you are looking for these modules, look in that file: they are there" and indeed that's what the optimization process does.
Related
I have a vue.js/Phoenix app. I'm trying to understand how to properly configure the frontend assets. I'm having trouble understanding why my priv/static/js/app.js file keeps updating whenever I Change something in other files. I'm trying to research this behavior but I can't seem to find out any information.
app.html.eex
<body>
<%= render #view_module, #view_template, assigns %>
<script src="<%= static_path(#conn, "/js/app.js") %>"></script>
</body>
My basic question is how to structure a vue.js app? The fact that I change something in asset/src dynamically changes something in static/js/app.js seems really strange. Does anybody have resources or answers on what might be happening here or places I can go to learn more?
In addition to what Pawel said, this behaviour might be intentionally configured. There is the watcher specified in config/dev.exs:
watchers: [
node: ["node_modules/brunch/bin/brunch", "watch", "--stdin",
cd: Path.expand("../assets", __DIR__)]]
That would be used in development mode to allow so-called “hot reload”: one does not need to reload the application when some changes in assets are made, app.js will be rebuilt and reloaded automagically.
There is also assets/brunch-config.js file, where one might specify rules of how the resulting app.js is being produced. By default is just compiles everything found in assets to the single javascript file, but this behaviour might be easily changed (e.g. one might exclude anything from being built into app.js and specify their own rules to provide an access to these excluded files.)
As contrary as this might sound, this is exactly the behaviour Phoenix (with Brunch) provides.
The main idea is to implement your JS functionality in assets/js/app.js, then Brunch (http://brunch.io/) as a build tool will take the content, compile/transpile and output to priv/static/js/app.js.
This means, with default configuration that comes with Phoenix, you can use ES6 in your code in assets/js/app.js, but this will be "translated" to executable form (that's understood by browsers), and located in priv/. priv/static is exposed publicly, and this will be the content available by:
<script src="<%= static_path(#conn, "/js/app.js") %>"></script>
To wrap up.
Code in priv/static is not meant to be changed by code, it gets there automatically by changes you put under your source control in assets/.
If that's any help, you can take a look at one of old blog posts about assets in Phoenix here.
Good luck!
I have been happy using webpack with Vue as of now. It uses a similar, configurable, watcher as the one mentioned by mudasobwa. In Webpack if you touch a file that is in part of the bundle it will recompile the needed files only (which can still be many depending on the dependency graph), probably brunch recompiles all.
I also use Yarn to manage npm, and I always include vuex unless it's really something just basic (although not related to file organisation it does help a lot organising vue on any non-trivial apps). Then
/assets
js
entry point files that I use for webpack output into its own individual bundles/apps
folders to organise these, usually /components-views-related, /store-related, /shared-utilities
css
.scss files, divided so that they can be split into "global" styles and individual styles that then are required in each "entry point". Then I use a "general" scss stylesheet on "all pages" and each page the corresponding css bundle where they're needed.
Then on the templates side, I wrote a small, overly complex, brittle, system to just automate the "bundle" that gets loaded on the template (in the html document head) but you can just load each bundle/s where you need them.
I have a very strange requirement that I need to bundle everything together in one HTML page with my Durandal Single Page application. I can make this away with my dependencies as I am defining them with a name:
define("models.mapper", [], function() {
});
However, it seems like it will not be possible to bundle durandal stuff as it defines modules without names:
define(['require', 'jquery'], function(require, $) {
// ....
}
This is fine when you want to make it work with path references but it seems like this will make it hard to inline this into HTML. Any ideas or suggestions on this?
Require.JS requires you to have only one anonymous define per file so that it can use the file path+name relative to the base path to give it a name. If you would like to have the durandal source inline on your page as well then you'll need to update their define lines to give them the appropriate names (i.e. define('durnadal/system', ......).
An easier approach may be to just build your source code in the structure of a normal durandal project and then use the RequireJS optimizer (http://requirejs.org/docs/optimization.html) to build them into a single JS file - if you configure this correctly without minification then you can just paste the file contents into a script tag on your page and it'll still be legible!
If you really wanted to you could then just continue developing in the single HTML file however you really should look at automating all of this into a grunt workflow and it shouldn't be too hard and you'll have much easier to manage code. Note that you may even be able to use the durandal grunt task to do this, but I'm not sure what options it allows you to provide but you can definitely use the requirejs grunt task and build it into your workflow without minification. With some templating task you could then inject that output into your final HTML page.
I'm an experienced javascript programmer, and I'm trying to write my own modular game engine from scratch. I haven't used requirejs before, but after reading a bit about it, it sounds like it's probably the best way to manage all the components of the engine and load them into one coherent structure.
My main problem is that I'm not really sure how to really use requirejs. I've been looking over their API documentation, but I'm not sure how to integrate it with the way I've laid out my project.
Currently, my project uses the following structure:
src
engine.js //This contains the common engine stuff, most notably the engine namespace
resource
resource-module.js //This is the module constructor, which handles all the common stuff between the different
substructures
sprites.js //This is a substructure that contains sprite loading code
render
etc...
third-party
jquery
requirejs
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can find my current source here: https://github.com/superlinkx/lithium-engine
I know the current code is messy, and there isn't a whole lot built yet, but I'm mostly still figuring out how to best structure it. Any help/advice would be appreciated, but my main concern is how to structure it with requirejs so that it will be easier to compile into a single file for production use.
Require.js does not enforce any specific structure of your files. You can either specify the full paths in the require configuration, or just use the full path in the require() or define() calls. Both will work, however the latter will save you some typing and makes it easier to move stuff around when you include something from a lot of different places:
var $ = require("third-party/jquery");
require.config({
paths: {
"jquery": "third-party/jquery"
}
});
var $ = require("jquery");
I want to be able to load the modules independently of each other. It should be possible for instance to remove the audio module from the engine, and it still work. It should also be easy to substitute modules, or add new modules.
This is not something require.js does four you. You can decide when and when not to load it, but you would have to make sure that it won't break the rest of your code.
Also, I'm using jQuery for event handling, so it needs to be loaded before the engine is initiated.
You can do this in several different ways.
require() it in your main.js so that it is always loaded (you can also use the require-jquery.js, which has jQuery included).
Specify jQuery as a dependency of your engine
require.config({
paths: {
"jquery": "path.to.jquery",
"engine": "path.to.engine"
},
shim: {
"engine": {
"deps": ["jquery"]
}
}
});
Pass jQuery to the define() call in your module (probably the best choice)
define(["jquery"], function ($) {
// your engine code
}
I have a rather large multi-page website. Each page will require a set of common js libraries (jquery, etc) as well as at least one js file specific to that page (that sets up an js functionality specific to said page).
I can have one config file for the entire site that sets up all my paths. This seems like the logical choice so that a config file for the paths needed for a specific file will not be needed for each page (a pain to maintain, and essentially negates what I am trying to do with requirejs).
However, part of me cringes at the idea of having paths available to a page that will never need them.
Question: What is recommended approach: use one combined require.config or multiple smaller configs (common + one-per-page)?
Note: I will be pulling js files from a CDN so none of the paths will be local, which I know isn't really a concern with the config file.
Generally I'd advise bundling your paths together, not only does this tend to be a convention other developers will expect. It also means your options can be re-used by the build tool by simply pointing it to file containing your config options.
However, if you really would like to separate the options then multiple calls to require.config() are permitted and the config object will simply be mixed.
require.config({
paths: {
'moduleA': 'bla/bla'
}
})
require.config({
paths: {
'moduleB': 'bla/bla2'
}
})
This is a complete noob question, but I gotta ask it anyway
I started playing with backbone.js a few days ago and I was really fascinated. As I got over the "ToDo", I started working on a project of my own. Coming from the world of Java, I prefer keeping everything in as many separate files as possible. Therefore, I split my models views, and routers into separate files, into separate folders.
The problem came when I tried to combine those fiels into one single applciation.js file. Again, coming from the Java world, I love when I can automate stuff, and even more, when I can use familiar tools like ant, to setup build processes for my javascript projects.
I got a sample ant build template which concatenates and minifies all the files in an arbitrary order. When it finished, I tried to run my JS app, and not surprisingly, it failed with a bunch of errors. Many of my models and views try to extend each other, others depende on them as components. If they are not defined in a proper order, the app just reaches a point where it is trying to execute extend of an undefined
I know from before that for JavaScript the order is very important, but somehow I was left with the impression that if all the scripts are in one single file, the JS parser will load all the stuff first and then will try to execute whatever is to be executed. Well, my assumption was wrong.
It is possible to list all the files in the specific order I want them, but do I really need to go for such a primitive step? Unfortunately after spending a few hours researching, I couldn't find anything better.
Is it really possible to concatenate JS files, which depend on each other, in an arbitrary order, without them clashing? I guess, the biggest problem is the fact that the extend function is actually being called, rather than each script simply defining and object literal
So, what's the solution?
UPDATE: I just saw that Sproutcore has its own builder. If SC is roughly similar to BB, in the way one creates and extends entities, how does the SC builder work without clashing?
There are many ways to do this, but here's my recipe. I prefix my development files with a number, starting from the one with no dependencies (base "classes", models that will be depended upon from other models, then views using these models, then routers calling those views, etc.).
Then I use uglify-js (available as a node.js library, that you install using npm install uglify-js) to minify all my js in one file (don't know from your question if you use node.js server-side, though). Then I cat *.js | uglifyjs -o min/myfile.min.js. This will send the content of all my .js files (respecting the order of dependencies because of my prefix) to uglify, which will minify it and save it to a single file.
Since I, too, like automation, I have this set up in a Makefile, though I guess it could be done using Ant (not too familiar with it). The relevant part of the Makefile look like this:
TARGET_MIN_FILE = public/js/min/myfile.min.js
JS = $(shell echo public/js/*.js)
public/js/min/myfile.min.js: $(JS)
cat $(JS) | uglifyjs -o $(TARGET_MIN_FILE)
clean:
rm -f $(TARGET_MIN_FILE)
.PHONY: clean
On the other hand, if you go for the asynchronous module definition (AMD) format, you can require() your modules and it will manage for you the dependency loading in the correct order (see Require.js for more info), as mentioned by TheShelfishMeme.
Your "assumption" is only true for var statements and functions of the form function name(a,b) {}. Those two get hoisted to the top of the script (or function block they are in) and are evaluated first.
If your files depend on other files being loaded first, it stands to reason that when you concatenate them they must be in that order in the final file.
Have a look at requirejs. It takes some time to set up but it should help you with your problem.
This article should help with the implementation.