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.
Related
Architecture
I would like to share code between client and server side. I have defined aliases in the webpack config:
resolve: {
// Absolute paths: https://github.com/webpack/webpack/issues/109
alias: {
server : absPath('/src/server/'),
app : absPath('/src/app/'),
client : absPath('/src/client/'),
}
},
Problem
Now on the server side I need to include webpack in order to recognize the correct paths when I require a file. For example
require('app/somefile.js')
will fail in pure node.js because can't find the app folder.
What I need (read the What I need updated section)
I need to be able to use the webpack aliases. I was thinking about making a bundle of all the server part without any file from node_modules. In this way when the server starts it will use node_modules from the node_modules folder instead of a minified js file (Why? 1st: it doesn't work. 2nd: is bad, because node_modules are compiled based on platform. So I don't want my win files to go on a unix server).
Output:
Compiled server.js file without any node_modules included.
Let the server.js to use node_modules;
What I need updated
As I've noticed in https://github.com/webpack/webpack/issues/135 making a bundled server.js will mess up with all the io operation file paths.
A better idea would be to leave node.js server files as they are, but replace the require method provided with a custom webpack require which takes in account configurations such as aliases (others?)... Can be done how require.js has done to run on node.js server.
What I've tried
By adding this plugin in webpack
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"ignore", /* filename= */"server.bundle.js")
Entries:
entry: {
client: "./src/client/index.js",
server: "./src/server/index.js",
ignore: ['the_only_node_module'] // But I need to do that for every node_module
},
It will create a file server.js which only contains my server code. Then creates a server.bundle.js which is not used. But the problem is that webpack includes the webpackJsonp function in the server.bundle.js file. Therefore both the client and server will not work.
It should be a way to just disable node_modules on one entry.
What I've tried # 2
I've managed to exclude the path, but requires doesn't work because are already minified. So the source looks like require(3) instead of require('my-module'). Each require string has been converted to an integer so it doesn't work.
In order to work I also need to patch the require function that webpack exports to add the node.js native require function (this is easy manually, but should be done automatically).
What I've tried # 3
In the webpack configuration:
{target: "node"}
This only adds an exports variable (not sure about what else it does because I've diffed the output).
What I've tried # 4 (almost there)
Using
require.ensure('my_module')
and then replacing all occurrences of r(2).ensure with require. I don't know if the r(2) part is always the same and because of this might not be automated.
Solved
Thanks to ColCh for enlighten me on how to do here.
require = require('enhanced-require')(module, require('../../webpack.config'));
By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!
Related
https://www.bountysource.com/issues/1660629-what-s-the-right-way-to-use-webpack-specific-functionality-in-node-js
https://github.com/webpack/webpack/issues/135
http://webpack.github.io/docs/configuration.html#target
https://github.com/webpack/webpack/issues/458
How to simultaneously create both 'web' and 'node' versions of a bundle with Webpack?
http://nerds.airbnb.com/isomorphic-javascript-future-web-apps/
Thanks
Thanks to ColCh for enlighten me on how to do here.
require = require('enhanced-require')(module, require('../../webpack.config'));
By changing the require method in node.js it will make node.js to pass all requires trough the webpack require function which allow us to use aliases and other gifts! Thanks ColCh!
My solution was:
{
// make sure that webpack will externalize
// modules using Node's module API (CommonJS 2)
output: { ...output, libraryTarget: 'commonjs2' },
// externalize all require() calls to non-relative modules.
// Unless you do something funky, every time you import a module
// from node_modules, it should match the regex below
externals: /^[a-z0-9-]/,
// Optional: use this if you want to be able to require() the
// server bundles from Node.js later
target: 'node'
}
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.
There are several Javascript files, organized in folders Scripts/folder1, Scripts/folder2, ...
With requirejs.config.baseUrl a folder is defined as the default, for example Scripts/folder1. Then in requirejs.config.paths some files are addressed with just the filename, and some are addressed with a relative path (like ../folder2/blabla).
When coding the Typescipt file folder2/blabla.ts we need the module "math" from folder1. So we write
import MOD1 = module("../folder1/math");
Regarding Typescript, anything is fine with that. It can find the module. However, with requirejs there is a problem. It does not know the module "../folder1/math", it only knows "math".
The problem seems to be that the import statement expects a filename, being adressed by starting from the current directory. However, this isn't the module id that requirejs knows about.
Using absolute paths anywhere, both in the requirejs configuration and the import statement in Typescript, solves the problem.
Am I doing this wrong? Or are absolute paths the way to go?
Specify a baseUrl to be equivalent to the root folder of your Typescript files:
require.config({
baseUrl: './scripts',
}
)
Then when you use relative paths starting from the scripts folder you can just do import like you normally do in typescript and requirejs will be using the same base path.
Update: This presentation should should answer all your url / using js from Typescript questions: http://www.youtube.com/watch?v=4AGQpv0MKsA with code : https://github.com/basarat/typescript-amd/blob/master/README.md
In you require configuration specify paths for each module. That should solve paths problem:
require.config({
paths: {
jquery: 'libs/jquery-1.7.1.min',
jqueryui: 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.9.2/jquery-ui.min'
// Other modules...
}
});
I've got some paths configured in require-config.js as follows:
var require = {
baseUrl: '/javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
// etc. -- several paths to vendor files here
},
}
I am trying to get the optimization working for deployment. The docs say I should have a build.js that looks something like this:
({
baseUrl: 'javascript',
paths: {
'jquery': 'jquery/jquery-1.8.1.min'
},
name: 'main',
out: 'main-build.js'
})
Is there a way to have the optimizer read my config file instead of (or in addition to) build.js? I don't want to have to manually keep the paths configured the same in both files if they change.
I tried to just run node r.js -o path/to/require-config.js, but it threw an error, "malformed: SyntaxError: Unexpected token var"
Edit: for clarification, my require-config.js file is the config only, not my main module. I did this so I could use the same configuration but load a different main module when unit testing.
You'll need to adjust the way your config options are defined. Taken from the RequireJS documentation:
In version 1.0.5+ of the optimizer, the mainConfigFile option can be used to specify the location of the runtime config. If specified with the path to your main JS file, the first requirejs({}), requirejs.config({}), require({}), or require.config({}) found in that file will be parsed out and used as part of the configuration options passed to the optimizer:
So basically you can point your r.js build file to your config options that will also be shared with the browser.
You will need to make use of the mainConfigFile option
For other's reference:
https://github.com/jrburke/r.js/blob/master/build/example.build.js
The build settings (no need to repeat your config.js lib inclusions here):
baseUrl: 'app',
name: 'assets/js/lib/almond', // or require
// Read config and then also build it into the app
mainConfigFile: 'app/config.js',
include: ['config'],
// Needed for almond (and does no harm for require)
wrap: true,
I have code like the following
define("ModuleA", ["InitialDependency"], function (initDep){
return {};
});
define("ModuleB", ["ModuleA", "OtherDependency"], function (moduleA, otherDep){
return {};
});
Each of these modules is defined in separate files "ModuleA.js", "Moduleb.js", "InitialDependency.js" and "OtherDependency.js".
These modules are loaded sequentially in my application. ModuleB is always loaded after ModuleA. this means that in the optimization stage I do not want ModuleA's script combined in the built script for ModuleB. I want the following
ModuleA.built.js includes
InitialDependency
ModuleA
ModuleB.built.js includes
OtherDependency
ModuleB
I don't want them all in the same file however as ModuleB may never be loaded.
I can do a build script for both modules but this will be time consuming as I have quite a few modules in my project and would like a build script that will build the lot of them at once.
What do I need to know to create a build script for building both of these modules (and more that follow the same dependency pattern)?
To achieve this, you'd have to play with the modules configuration option.
It could look like this:
{
modules: [
{
name: "ModuleA",
include: [],
exclude: []
},
{
name: "ModuleB",
exclude: [
"moduleA"
]
}
]
}
There's a similar example setup by James here: https://github.com/requirejs/example-multipage
Of course, by building these modules separately, you may end up needing to update paths. If so, the best way then would be to create a file containing a require.config call with special setting for your builded app and including this configuration instead of your usual one. But if you set dependencies in a good separated way, then you'll probably be fine. By "good separated" way, I mean that if moduleA is the base script, then it shouldn't have dependencies packed with moduleB - but I guess this is common sense!
Note about shimmed modules: As shimmed config only work whe files are loaded and by r.js to order plugins, be sure you don't include a shim module without it's dependency if you're not 100% sure these will be loaded before. More info here: https://github.com/requirejs/example-multipage-shim
Hope this help!