Require.js optimizer supposed to copy all files over into the output directory? - requirejs

I am trying to integrate the r.js optimizer on the server side (Apache Sling) and face one problem: when resolving modules it always looks them up under the output directory (dir), not from within the source directory (baseUrl or appDir), doesn't find them and thus fails.
/project/build.js
({
name: "modules/main",
dir: "/target",
baseUrl: "/sources"
})
If you wonder, the root path / is inside the server's JCR repository, not a file system. Also I simplified the example a bit (hopefully without concealing the issue).
It will resolve and read the main file properly:
/sources/modules/main.js
require(["modules/foo"]);
However, when it now tries to resolve modules/foo, it tries to read it from /target/modules/foo.js instead of /sources/modules/foo.js as I would expect, which does not exist and the whole r.js execution fails and stops.
I tried using appDir and all kinds of combinations, but the issue is always the same. I am fairly sure it is not related to my integration code... AFAIU from documentation and googling around, it should either copy them to the target before building the optimized file or simply pick them up from the source directory automatically.
Am I supposed to copy all the raw source files to /target myself before running r.js?
Maybe the problem is that baseUrl=/overlay is different from build.js residing inside /project?
Maybe r.js also looks at the current working directory of the r.js process (which is so far undefined in my case)?
Can the output directory (dir) live outside appDir or baseUrl?

My require.js configuration looks like so:
({
appDir: "../app",
baseUrl: "js/lib", // means the base URL is ../app/js/lib
dir: "../app-built", //target
// offtopic, but a very handy option
mainConfigFile: "../app/config.js",
// I'm not 100% sure if it's equivalent to your version
// where you're not using "modules" and just "name"
modules: [{
name: "../some/main" // this is ../app/js/some/main.js
}]
})
Reading through https://github.com/jrburke/r.js/blob/master/build/example.build.js#L15 - it seems you do want an appDir specified if you want the files to be copied to the target dir before optimization.
To answer your other questions
you don't need to manually copy files over
baseUrl should point to the same place as baseUrl used in your app's config - however you have to adjust it depending on what appDir you choose to use (e.g. appDir="../app" and baseUrl="js/lib", or appDir="../app/js" then baseUrl="lib", etc.)
appDir and dir should be relative to the build config file - I don't know what happens when you use absolute paths
yes - output dir does (has to?) live outside appDir. BaseURL is within the appDir/dir (all these names are really confusing..)
I would say
use the "appDir" setting
try using "modules" like I did instead of just "name"
make "appDir" and "dir" relative paths to the build file if you can - these absolute paths might be what's breaking? because other than that the config looks very similar to the one I use
I know there's a different way of configuring it where your output is 1 file, which case the files are read from the source dir - but I haven't used that much myself.
Hope this helps.

Answering myself: I got it to work with the single output file approach using out instead of appDir or dir:
({
name: "modules/main",
baseUrl: "/sources"
out: "/target/out.js",
})
In this case it reads all the modules from the sources and creates a /target/out-temp.js which it then moves to /target/out.js when done.
This seems to suit my needs so far.

Related

How to share npm modules across projects?

I'm using windows 10 x64.
I'm using dropbox to hold all my projects, and having a 'node_modules' folder inside a dropbox folder is a disaster.
First of all not all npm packages work in a way that would allow this method , because as it says in line one " does not begin with '/', '../', or './' ", so that won't work I think.
So, I tried to make syslink, but as I figured out, windows doesn't allow creating true hard links for folders, only files.
My method to create a folder junction was to have this bat file inside each project folder, and run it as administrator.
SET dest=%~dp0node_modules
SET src=F:\work\node_modules
MKLINK /J %dest% %src%
The bat file works, it creates the syslink, but 3 problems occur.
Dropbox sees it as a real folder and starts syncing it.
That folder doesn't show in the selective syncing to prevent syncing it.
npm can't use it for some reason and when I run 'npm install', It creates a new real 'node_modules' folder to replace the syslink, I get this error output:
I would not try to use junctions, they are pretty hard to work with and can lead to data loss if you don't know what you're doing.
Instead, you could go with the following approach.
Create a json config file containing the path to your modules:
{"modules_root": "F:/work/node_modules/"}
In your code, load this json and require your modules by prepending the path from your config file:
var fs = require("fs");
var modules_root = JSON.parse(fs.readFileSync("modules_root.json")).modules_root;
var express = require(modules_root + "./express")
If you ever decide to use local modules, you could just change the config file to:
{modules_root: "./node_modules/"}

Nodejs difference between ./folderpath vs ../folderpath

I'm new in nodejs. I try to use some file in my filesystem. I would like to get them through some realtive path. Here is the structure:
-app
-resources
-tmp
-file1
-file2
-common
-common.js
-etc
So, I would like to reach the file1 and file2 in my resources/tmp folder from the common.js file in int common folder. I used two relative path methodic:
// First , wrong one
var tmpfolder = '../resources/tmp';
// Second, good one
var tmpfolder = './resources/tmp';
The file absolute path is something like this:
C:\Users\xy\Documents\work\nodejs\projects\project_wrapper_folder\project_folder\resources\tmp
If I log the first relative path I got this result:
C:\Users\xy\Documents\work\nodejs\projects\project_folder\resources\tmp
which is wrong, because it does not contains the wrapper folder.
But the second works fine.
Can somebody explain me this behaviour?
UPDATE
I see the meaning if '../', thanks your explanations!
I have tried #Lissy answer: "So baring that in mind ./ will resolve to the value of your project root..." that sounds great, but the result is not.
I have this logic in my app:
var tmpfolder = require('./otherFolder/orhetFile');
where otherFolder is the subfolder of my project_folder. So, when I used this here, I got an error called Cannot find module ...
But if I use this './' in fs module, here: /project_folder/otherFolder_2/otherFile_2 like:
var path = `./resources/tmp`;
fs.mkdirsSync(path);
It works!
these is strange for me. If './' means the current folder, than the example above sould not work (but it's works).
But if the './' means path of the project root, the example with require should work (but does not work).
Strange for me, is there some meaning of require or fs??
In Summary
./my-file means look at the root, whereas ../my-file, means come out of the current directory, and look in the parent folder.
Explanation of Relative and Absolute Paths in Node.js
The default document root is set with the NODE_PATH environment variable (however it would be terrible practice to modify that). So baring that in mind ./ will resolve to the value of your project root.
And so let tmpfolder = require('./resources/tmp'); would resolve to
C:\Users\......\project_wrapper_folder\project_folder\resources\tmp as you have seen
A relative path is denoted by not starting with ./, so for example let tmpfolder = require('my-scripts/some-script'); would look in the current directory for another folder called my-scripts.
Following on from that ../ is relative to the current directory, but goes out one (to it's parent) and looks from there. You can go out two directories by doing ../../my-dir and so on (this is not great practice though, as it can get hard to manage if you have ../../../../../../)
Better method
You can use the __dirname constant in Node to locate the directory name of the current module.
e.g.
fs.readFile(__dirname + '/../foo.bar');
Useful Links
I think you'll find this article on Better local require() paths for Node.js very useful.
Also, for a bit of further reading, here is the official Node.js documentation on paths
The .. means the previous dir. So you are getting out from project_wrapper_folder and then add to the script dir resources\tmp and that way the project_wrapper_folder is no longer in the relative path.
Lets assume you are inside a folder called app.
when you use ../resources/tmp, it will come out of the app folder and will search for tmp inside resources folder.
when you use ./resources/tmp, it will look within the app folder for resources folder and tmp inside it.
../ points to the parent directory while ./ points to current working directory.
A dot basically means "go one folder back in the path"
So:
'./' points at the folder you are in.(in your case the folder common/)
'../' points at the folder that contains the folder you are in. (in your case the folder app/)

Require.js r.js: Compile directory to single file

Is there any way to configure RequireJS to compile an entire directory to a single file? I don't mean the normal use case of the 'out' setting. I'll try to explain by example. If I have the following project structure:
- app
- main.js
- menu.js
- module
- file-a.js
- file-b.js
Then let's say I want to compile the 'app' directory to a single file. I don't care about it's dependencies - even if it requires 'module' or either of its files, they won't be included. Even if main.js doesn't require menu.js, it'll be included anyway. The resultant output file would define 'app/main' and 'app/menu' modules.
Likewise, if I wanted to compile the 'module' directory, the file would define 'module/file-a' and 'module/file-b' regardless of what other dependencies were defined.
I hope this is clear enough.
You can use the dir parameter in build file of require instead of just name parameter.
You can read more about building whole directory on requirejs documentation - Optimize Whole Project
If you write build file something like app-build.js-
({
appDir: ".",
baseUrl: "app",
dir: "../app-build",
})
and if you run r.js -o app.build.js then it will create
app-build
main.js
menu.js
Here menu.js will not be include in main.js unless it is required somewhere in main.js source.

grunt-usemin block paths not relative to html file?

Having a lot of trouble understand how paths are treated at various points in the configuration and usage of grunt-usemin.
I've got the following repo layout, where the repo root will also be the web app root:
/dashboard/index.html
/Gruntfile.js
/vendor/...some 3rd party CSS and JS...
So the index.html file -> somedomain.com/dashboard/index.html.
The index.html file includes some CSS and JS assets from the /vendor folder. I have grunt configured to put build output in a build folder:
/build/dashboard/index.html
In the index.html file, I have usemin blocks wrapped around all the CSS link and JS script tags:
<!-- build:css(.) app.min.css -->
<!-- build:js(.) app.min.js -->
I had to specify an "alternative search path" with "(.)" so that a script tag for "/vendor/backbone.js" will find it in the right place. Until I did that, it was looking for /dashboard/vendor/backbone.js.
I want the output of processing the CSS/JS assets to be output to build/dashboard/app.min.css and build/dashboard/app.min.js, and included by index.html using a simple relative "app.min.css/js" path.
The problem is, grunt-usemin seems to be using the "app.min.*" path I'm specifying for both contexts in a way that makes it impossible for them to work together:
1) It treats the path as relative to the build directory for purposes of creating the file; the files end up in build/app.min.css and build/app.min.js.
2) It treats the path as relative to the index.html file for purposes of generating the new link/script tags; the browser loads build/dashboard/index.html, which then tries to load "app.min.css", which maps to build/dashboard/app.min.css.
Is there a solution?
I'm really late to the party, but I was also extremely frustrated by this issue and didn't find any satisfying fixes or work arounds. So I worked out some pretty dirty tricks to hopefully better work around this issue. So I'd like to share it with you.
First of all, let's quickly review why this issue happens. When usemin generates output JS/CSS files, it performs a simple path join between your dest directory and the output directory you specified in your usemin block. So if dest is build and usemin block is
<!-- build:css(.) app.min.css -->
then it joins build with app.min.css to spit out the output file at build/app.min.css
But then the usemin task simply replaces the path in your block to you end up with
<link rel="stylesheet" href="app.min.css"/>
which is now linking the wrong directory since your HTML file is under build/dashboard/index.html
So my work around revolves around this idea: what if dest directory is relative to where the HTML file is located? Wouldn't that solve this issue? So given the above example, what if dest is build/dashboard? You can see that it will spit out the output file location and link it correctly. Keep in mind that you are supposed to create a copy task to copy over your HTML files, so make sure your HTML file is copied to build/dashboard/index.html as before.
Of course, the next question would be what if I have HTML files in multiple directories? Wouldn't that be super painful and unintuitive to create a useminPrepare target for each directory, where HTML files could reside? This is why I create a very special grunt task just for working around this issue while I was creating my own grunt scaffolding. I call it useminPreparePrepare Yes, it's deliberately named stupidly, because I'm hoping to remove this thing altogether one day when usemin people make an actual fix for this issue.
As its name suggests, this is a task to prepare useminPrepare configs. It does exactly what I described above. All of its configs mirror useminPrepare configs (in fact, most of them are simply copied over to useminPrepare), with one exception: you need to specify a src directory to identify the root directory of all of your sources so that it can generate relative path to the HTML files. So in your example src: "." will be fine. To use useminPreparePrepare, import it into your build first (you may want to just copy and paste my code, I don't mind), rename your useminPrepare task to useminPreparePrepare and add src property that I just mentioned. Make sure you run useminPreparePrepare with whatever target you like, then immediately run useminPrepare without specifying target so that all of its targets are run. This is because useminPreparePrepare will generate one target for each directory relative to where HTML files are found and copies over your configs for the useminPreparePrepare target your ran. This way, your config can simply look for all HTML files.
Example
"useminPreparePrepare": {
// Search for HTML files under dashboard even though src is .
// because we want to avoid including files generated under build directory.
html: "dashboard/**/*.html",
options: {
src: ".",
dest: "build",
...
"usemin": {
html: ["build/**/*.html"],
...
"copy": {
html: {
files: [{
expand: true,
src: ["dashboard/**/*.html"],
dest: "build"
}
]
},
...
Hope this helps! Have a good day.
EDIT: I realized that given the above example, if you actually include all HTML files from current directory, you will include the generated HTML files too if they are not cleaned ahead of time. So either you clean them ahead of them or look under dashboard directory. I'd recommend separating src and dest directories so that config could look a lot more intuitively.
I don't like it, but the only way I've found to make it work so far is to specify a full path:
<!-- build:css(.) /dashboard/app.min.css -->
<!-- build:js(.) /dashboard/app.min.js -->
The leads to the app* files being in /build/dashboard alongside index.html (which is where I want them), and index.html ends up with the following tags:
<link rel="stylesheet" href="/dashboard/app.min.css">
<script src="/dashboard/app.min.js"></script>
It means the dashboard app is now acutely aware of it's location within the whole, so you can't just rename or relocate it's position in the tree without updating those paths.

Loading vendor javascript as modules

I'm working on an application built with Brunch. I would like to load some* of the vendor-supplied javascript as modules, so that I can require them in my code, rather than relying on global variables. Is there some way to do this, without copying all the vendor code into my app directory?
I tried creating a vendorlib directory, but brunch doesn't seem to look anywhere bu app and vendor. I also tried making a vendor/modules directory, but brunch seems to not wrap anything found under vendor (even when I convinced it to combine those files with the files other modules found under app.)
*The "some" that I'm working on right now are Chaplin, Backbone and Underscore. If I get those to work, I'll move more over later.
You can override config.modules.wrapper and make it wrap, for example, all files in vendor/modules directory. Or you can make add more directories that are handled by brunch to config.paths.watched.
For those following along at home, this is what my config.coffee eventually looked like:
paths:
watched: ['app','vendor','test','vendorlib']
files:
javascripts:
joinTo:
'javascripts/app.js': /^app/
'javascripts/vendor.js': /^vendor/
'test/javascripts/test.js': /^test[\\/](?!vendor)/
'test/javascripts/test-vendor.js': /^test[\\/](?=vendor)/
order:
# Files in `vendor` directories are compiled before other files
# even if they aren't specified in order.before.
before: [
'vendor/scripts/console-polyfill.js',
]
after: [
'test/vendor/scripts/test-helper.js'
]
stylesheets:
joinTo:
'stylesheets/app.css': /^(app|vendor)/
'test/stylesheets/test.css': /^test/
order:
after: ['vendor/styles/helpers.css']
templates:
joinTo: 'javascripts/app.js'
modules:
nameCleaner: (path) ->
path.replace(/^(app|vendorlib)\//, '')
This lets me populate a vendorlib directory with modules from vendors that support loading as modules. I currently have Chaplin, jQuery, and Backbone in there. I had to rename them not to include the version numbers.

Resources