I have been looking into integrating testing into my app based on RequireJS. I have found this example of how QUnit testing could be integrated into the RequireJS structure. Obviously you don't want the testing code to be lying around in the Production build. How can you keep testing out of the final production build in RequireJS?
There are lots of options you can set in the build file. See the full example on GitHub (https://github.com/jrburke/r.js/blob/master/build/example.build.js)
What you want to do is exclude certain items from your module:
//This module entry combines all the dependencies of foo/bar/bip into one file,
//but excludes foo/bar/bop and its dependencies from the built file. If you want
//to exclude a module that is also another module being optimized, it is more
//efficient if you define that module optimization entry before using it
//in an exclude array.
{
name: "foo/bar/bip",
exclude: [
"foo/bar/bop"
]
},
//This module entry shows how to specify a specific module be excluded
//from the built module file. excludeShallow means just exclude that
//specific module, but if that module has nested dependencies that are
//part of the built file, keep them in there. This is useful during
//development when you want to have a fast bundled set of modules, but
//just develop/debug one or two modules at a time.
{
name: "foo/bar/bin",
excludeShallow: [
"foo/bar/bot"
]
}
You can also exclude items with a regular expression, but this is probably overkill:
//When the optimizer copies files from the source location to the
//destination directory, it will skip directories and files that start
//with a ".". If you want to copy .directories or certain .files, for
//instance if you keep some packages in a .packages directory, or copy
//over .htaccess files, you can set this to null. If you want to change
//the exclusion rules, change it to a different regexp. If the regexp
//matches, it means the directory will be excluded. This used to be
//called dirExclusionRegExp before the 1.0.2 release.
//As of 1.0.3, this value can also be a string that is converted to a
//RegExp via new RegExp().
fileExclusionRegExp: /^\./,
Related
What does HashedModuleIdsPlugin do?
From Webpack docs:
This plugin will cause hashes to be based on the relative path of the module, generating a four character string as the module id. Suggested for use in production.
After reading it couple of times, I still can't understand why and when to use it and how it is related to the way I define a name to each bundle in output section:
filename: '[contenthash].[name].js',
I understand it this way, webpack 4.3 added contenthash, but before that, you can use HashedModuleIdsPlugin, I am not quite sure.
https://github.com/webpack/webpack/releases/tag/v4.3.0
By default, Webpack will create a list of modules (all the imported packages you have, as well as project files) and this list will be an array. The "module ID" (the pointer to the actual module code) will be the array index.
HashedModuleIdsPlugin will define this module list as an object, where the keys are the generated hash (from the relative file name) and the values will be the actual module code.
There is also the NamedModulesPlugin (if we're talking Webpack 3), which does the same thing but instead of a hash, the key is the actual relative path, for example:
"./node_modules/tiny-relative-date/lib/factory.js": function(e, t, n) {
In Webpack 4+, this was replaced by: https://webpack.js.org/configuration/optimization/#optimizationmoduleids
This is a portion of my build configuration for requireJS's optimizer, r.js.
exclude: [
'widgets/cr-log-display',
'widgets/cr-pager',
'widgets/cr-time-input'
My question is simply this: is it possible to exclude ALL dependencies starting with widgets/.
The docs don't seem to indicate that a regex, or anything similar can be passed here. Is there another configuration parameter that I'm missing?
I'm pretty sure you cannot pass a regular expression to exclude. I'm saying this from having read the source of r.js. The processing of exclude uses an internal function named findBuildModule, which compares what is passed to exclude against module names with ===. And by the same token, there is no way to tell r.js "exclude all modules under this directory".
The one avenue I see you might be able to use is onBuildWrite, which is a global setting that takes a function. I've used it for other purposes than what you want but perhaps this would do the trick:
onBuildWrite: function (moduleName, path, contents) {
return /^widgets\//.test(moduleName) ? "" : contents;
}
If the module name starts with widgets/ then the contents that will be written to the bundle will be the empty string, otherwise the contents will be whatever the module's contents happen to be.
Note that this will not do exactly what exclude does. The exclude setting excludes the listed modules and their dependencies. The onBuildWrite example above is an analogue to excludeShallow in that the modules that match the regular expression will be excluded but their dependencies won't be excluded. There is no way to easily write an onBuildWrite function that will extend the exclusion to dependencies of the modules that you'd like to exclude. r.js does not give an API to query dependencies of a module.
I am using requirejs optimizer (r.js) through grunt and here is my requirejs config :
requirejs.config
baseUrl: '/scripts'
locale: window.localStorage.getItem('locale') || null
...
The thing is that the grunt r.js plugin (https://github.com/gruntjs/grunt-contrib-requirejs) throw an error everytime I try to use a variable inside my requirejs config.
The main config file cannot be used because it cannot be evaluated correctly while running in the optimizer. Try only using a config that is also valid JSON, or do not use mainConfigFile and instead copy the config values needed into a build file or command line arguments given to the optimizer.
Have you managed to use a variable as a locale and r.js at the same time ?
Your locale setting acquires a real value only at runtime. For parts of RequireJS' config that can only be given values at runtime, what I do is:
Just call require.config (or requirejs.config) once with the information which is static. The config does not contain any variables. I point r.js to this static information.
At runtime, I have at least one additional call to require.config that sets those values that are to be computed. RequireJS combines multiple calls to require.config into one configuration.
r.js will only use the first configuration it recognizes in a file. So you may be able to just split your single requirejs.config call into a static and dynamic part and leave them in the same file.
I'm thinking about using require.js and it's optimzier to combine and minify a library that consists of more then one js-file. Every js-file contains one single module. But there is no main-module that requires (imports) all modules/js-files.
I want to combine all files in one file, that could be used as a library. In that way I could ship the library in one single file instead of several files.
Is this possible, or do I have to create some kind of a main-module that requires /imports all other modules?
Thanks for your help!
treeno
I've not tried it myself but you should be able to pass a build configuration to r.js that contains the following:
modules: [{
name: "my-lib.js",
create: true,
include: ["moduleA", "moduleB", ...]
}]
This tells r.js to put into a single file named my-lib.js all of the dependencies listed in include and tells it that there is no corresponding file named my-lib.js in your sources but that r.js should create it in the output. So the key is:
List all the modules you want in include.
Use create: true.
The documentation on the optimizer does not mention create but you can find it documented here.
I'd like to be able to install Javascript dependencies through bower and use them in a sails.js app, but I can't figure out a way to do this with out just copying an pasting files from the bower_components folder to the Sails assets folder.
Ideally I think I'd like to use requirejs and point to the bower components in the main.js file. I may be trying to pound a square peg in a round hole, please let me know if so. Any thoughts on managing components/libraries with Sails are welcome.
In Sails 0.10 the 'assets/linker' directory no longer exists, however I found a lead on simple solution that gives some automation to the bower -> asset linker workflow while also allowing some granular control over what exactly ends up getting linked.
The solution is adding grunt-bower to your Sails.js compileAssets task
grunt.registerTask('compileAssets', [
'clean:dev',
'bower:dev',
'jst:dev',
'less:dev',
'copy:dev',
'coffee:dev'
]);
Then configure your grunt-bower task like so (as tasks/config/bower.js):
module.exports = function(grunt) {
grunt.config.set('bower', {
dev: {
dest: '.tmp/public',
js_dest: '.tmp/public/js',
css_dest: '.tmp/public/styles'
}
});
grunt.loadNpmTasks('grunt-bower');
};
This will automatically copy your bower js and css files to the proper place for Sail's asset linker to find and automatically add to your project's layout template. Any other js or css files will still automatically be added after your bower files.
However this is still no silver bullet as this setup has 2 big caveats to it:
1 - The files that are added through bower-grunt have to be listed in bower.json's main array. If you see a file isn't being loaded you would expect to be, you must either edit that packages bower.json file OR add the dependency manually through grunt-bower's packageSpecific options.
2 - The order of bower files in the asset linker is currently alphabetical. My only recourse to adjust this order so far is tinkering around with an additional grunt task to manually re-order files prior to the rest of Sail's compileAssets task. However this one I'm confident there is something grunt-bower could do by supporting package copy ordering.
Note: the following answer is no longer completely relevant to the current version of SailsJS because there is no support for the linker folder as of SailsJS 0.10.
See: Sails not generating linker
Original answer:
I was able to figure out a solution for this, which is actually pretty simple. I had not realized you could configure where bower places it's files.
Create a .bowerrc file and change the directory where bower components are installed, in the case of Sailjs they should be put into the assets folder.
/*
* Create a file called .bowerrc and put the following in it.
* This file should be in the root directory of the sails app.
*/
{
"directory": "assets/linker/bower_components"
}
Sails will then use grunt to copy them to the .tmp/public/assets folder whenever a file is change. If you don't wish to have sails continually deleting and then recopying those files you can exclude them in the grunt file.
/*
* This is not necessary, but if you have a lot of components and don't want
* them constantly being deleted and copied at every file change you can update
* your Gruntfile.js with the below.
*/
clean: {
dev: ['.tmp/public/**',
'!.tmp/public',
'!.tmp/public/bower_components/**'],
build: ['www']
},
One tip on using requirejs with sails. By default you will get an error from the socket.io file since sails will load it without using requirejs. This will throw an error since socket.io supports amd style loading, more details here http://requirejs.org/docs/errors.html#mismatch.
The simplest way to fix this is to just comment out the lines near the end of the socket.io.js.
/*
* Comment the below out in the file assets/js/socket.io.js, if using requirejs
* and you don't want to modify the default sails setup or socket.io.
*/
if (typeof define === "function" && define.amd) {
define([], function () { return io; });
}
The other way would be to recode the sails files in assets/js named "socket.io.js", "sails.io.js" and app.js to be amd modules.
The simplest way I've found of achieving this is simply to add the individual Bower components to your tasks/pipeline.js file. For example, here's how you might add Modernizr:
// Client-side javascript files to inject in order
// (uses Grunt-style wildcard/glob/splat expressions)
var jsFilesToInject = [
// Load sails.io before everything else
'js/dependencies/sails.io.js',
// Dependencies like jQuery, or Angular are brought in here
'js/dependencies/**/*.js',
// =========================================================
// Modernizr:
'bower_components/modernizr/modernizr.js',
// =========================================================
// All of the rest of your client-side js files
// will be injected here in no particular order.
'js/**/*.js'
];
A link to bower_components/modernizr/modernizr.js then gets inserted in the <!--SCRIPTS--> placeholder in your layout template, and it also gets minified, etc, when you run sails lift --prod.
Sorry for my late.
I think include bower_components in linker it's a bad idea, because when you will lift sails, everything in it will be copied in .tmp and include in tags.
For example, if you have include Angular with bower, you will have two inclusions in your script: one for angular.js and one for angular.min.js. And having both is a mistake.
Here is my solution on my projects :
I have created a folder bower_component in my root directory.
I have added this line in my Gruntfile.js in the array files in copy:dev
{ '.tmp/public/linker/js/angular.js': './bower_components/angular/angular.js' }
And for each files I want to include, I need to manually add a new line in this array. I haven't find an another automatic solution. If someone finds a better solution... ;)
There is more than one approach to hooking up SailsJS and Bower.
A package for SailsJS that integrates Bower via a custom generator exists here:
https://www.npmjs.com/package/sails-generate-bower
There is one for Gulp as well.