How to expose a dependency when writing a grunt module - javascript

I'm building a module grunt-foo which is utilizing grunt-galvanize (e.g. its in my package.json as a dependency). Something like this:
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt)
grunt.registerMultiTask('foo', 'do your foo', function() {
grunt.task.run('bar');
});
grunt.registerTask('bar', function() {
// Add some galvanize configs
grunt.option('galvanizeConfig', { configs: { ... } });
grunt.task.run(['galvanize:baz'])
});
grunt.registerTask('baz', function() { grunt.log.ok('baz'); });
};
However, when I utilize this grunt module in an app and run grunt foo I get something like Warning: Task "galvanize:baz" not found. Use --force to continue.
I'm looking for a solution that does not involve my having to install grunt-galvanize as a dependency (dev or otherwise) within the apps that will utilize my grunt module.

Related

Bundling with webpack from script

I am using webpack to bundle my Javascript files in my project:
webpack --config myconfig.webpack.config.
From commandline it is ok.
Building
However I would like to create a build task, I am using jake, so in order to create the bundle I need to invoke webpack from Javascript.
I could not find the API online, I basically need something like this:
// Jakefile.js
var webpack = require("webpack");
desc('This is the default build task which also bundles stuff.');
task('default', function (params) {
webpack.bundle("path-to-config"); // Something like this?
});
How do I achieve this?
Attempt 1
I have tried the following:
// Jakefile.js
var webpack = require("webpack");
var config = require("./webpack.config.js");
desc('This is the default build task which also bundles stuff.');
task('default', function (params) {
webpack(config);
});
webpack.config.js is my config for webpack. When I use from commandline and reference that file the bundle is correctly created. But when using the above code it does not work. When I execute it, no errors, but the bundle is not emitted.
In your Attempt 1, you seem to be consuming the webpack's Node.js API by passing the config to webpack method. If you take this approach, webpack method will return a compiler object and you need to handle it correctly.
For e.g.,
import webpack from 'webpack';
var config = {}; // Your webpack config
var wpInstanceCompiler = webpack(config);
wpInstanceCompiler.run(function(err, stats) {
if (stats.hasErrors()) {
console.log(stats.toJson("verbose");
}
});
This is how you execute a webpack config via the Node.js API. Unless you run the compiler instance, the output will not get generated.
This worked for me as well:
var webpack = require("webpack");
var lib = require(path.join(__dirname, "webpack.config.js"));
desc('Builds the projects and generates the library.');
task('default', function() {
webpack(lib, function() {
console.log("Bundle successfully created!");
});
});

Require another file in gulpfile (which isn't in node_modules)

I've been using gulp for a while now and know how to import another node module, e.g.
var sass = require('gulp-sass');
That's fine, but my gulpfile is filling up with code that I'd like to move into a separate file and "require". Specifically I am writing a postcss plugin, which I already have working when declared as a function inside of the gulpfile. My question is how to put my function in an external file and require it like I do a node module. Do I need to "export" the function in the file being required? Do I need to use ES6 modules or something like that?
As an aside, I realise that if i was doing this probably I would either (A) turn this into a proper node module and put it on a private NPM repository, but that seems unnecessary, or (B) turn it into a proper gulp plugin, but that would require learning how to author a gulp plugin and learning about streams and stuff. Both of these are probably better but would take more time so I've decided to just keep the function simple and local for now.
First create a new js file (here ./lib/myModule.js):
//./lib/myModule.js
module.exports = {
fn1: function() { /**/ },
fn2: function() { /**/ },
}
You could also pass some arguments to your module:
// ./lib/myAwesomeModule.js
var fn1 = function() {
}
module.exports = function(args) {
fn1: fn1,
fn2: function() {
// do something with the args variable
},
}
Then require it in your gulpfile:
//gulpfile.js
var myModule = require('./lib/myModule')
// Note: here you required and call the function with some parameters
var myAwesomeModule = require('./lib/myAwesomeModule')({
super: "duper",
env: "development"
});
// you could also have done
/*
var myAwesomeModuleRequire = require('./lib/myAwesomeModule')
var myAwesomeModule = myAwesomeModuleRequire({
super: "duper",
env: "development"
});
*/
gulp.task('test', function() {
gulp.src()
.pipe(myModule.fn1)
.pipe(myAwesomeModule.fn1)
.gulp.dest()
}
First, you have to add export default <nameOfYourFile> at the end of your file
Then to use it, write import gulp from 'gulp'
If you have an error message, install babel-core and babel-preset-es2015 with NPM, and add a preset "presets": ["es2015"] in your .babelrc config file.
I fix my problem by install:
npm i babel-plugin-add-module-exports
Then i add "plugins": [["add-module-exports"]] to the .babelrc

How to execute jasmine tests for node modules from grunt

I want to run some Jasmine 2.x tests for node.js modules in a Grunt build. My setup looks like this:
src/foo.js
exports.bar = 23;
spec/foo.spec.js
var foo = require("../src/foo.js");
define("foo", function() {
it("exports bar as 23", function() {
expect(foo.bar).toBe(23);
});
});
With grunt-contrib-jasmine the node module system is not available and I get
>> ReferenceError: Can't find variable: require at
>> spec/foo.spec.js:1
There is grunt-jasmine-node, but it depends on jasmine-node which is unmaintained and includes Jasmine 1.3.1, so this is not an option.
Jasmine supports node.js out of the box, by including a file jasmine.json in the spec directory, I can run the tests with the jasmine cli. Is there any clean way to run the same tests from grunt as well?
You could use grunt-exec, which just executes the value as if typed on the command line:
module.exports = function (grunt) {
grunt.initConfig({
exec: {
jasmine: "jasmine"
},
env: {
test: {
NODE_ENV: "test"
}
}
});
grunt.loadNpmTasks("grunt-exec");
grunt.loadNpmTasks("grunt-env");
grunt.registerTask("test", [
"env:test",
"exec:jasmine"
]);
};
This will allow you to keep jasmine up to date as well as use it with other grunt tasks.

How should project-level bundling be handled for non SPA use?

I am learning browserify and I am trying to do two basic things with it:
Transform (via shim) non-CommonJS modules for ease-of-use and dependency tracking
Bundle the libraries that are project-specific
I've found a working process for how to do all of this and automate it with Gulp. This works and produces the right output but, I am curious if it could be made simpler. It seems like I have to duplicate a lot of configuration on the project-based bundles. Here is the working example:
package.json
invalid comments added for clarification
{
//project info and dependencies omitted
//https://github.com/substack/node-browserify#browser-field
"browser": { //tell browserify about some of my libraries and where they reside
"jquery": "./bower_components/jquery/dist/jquery.js",
"bootstrap": "./bower_components/bootstrap/dist/js/bootstrap.js"
},
"browserify": {
//https://github.com/substack/node-browserify#browserifytransform
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
//shim the modules defined above as needed
"jquery": {
"exports": "$"
},
"bootstrap": {
"depends": "jquery:$"
}
}
}
config.js
contains all task-runner related configuration settings
module.exports = {
browserify: {
// Enable source maps and leave un-ulgified
debug: true,
extensions: [],
//represents a separate bundle per item
bundleConfigs: [
{
//I really want to refer to the bundles here made in the package.json but
//if I do, the shim is never applied and the dependencies aren't included
entries: ['/bundles/shared-bundle.js'],
dest: '/dist/js',
outputName: 'shared.js'
}
]
},
//...
};
shared-bundle.js
acts as a bundling file where node loads the dependencies and at this point, the shim has been applied
require('bootstrap');
browserify-task.js
contains the browserify bundling gulp task
//module requires omitted
gulp.task('browserify', function (callback) {
var bundleQueue = config.bundleConfigs.length;
var browserifyBundle = function (bundleConfig) {
var bundler = browserify({
entries: bundleConfig.entries,
extensions: config.extensions,
debug: config.debug,
});
var bundle = function () {
return bundler.bundle()
// Use vinyl-source-stream to make the stream gulp compatible
.pipe(source(bundleConfig.outputName))
// Specify the output destination
.pipe(gulp.dest(bundleConfig.dest))
.on('end', reportFinished);
};
var reportFinished = function () {
if (bundleQueue) {
bundleQueue--;
if (bundleQueue === 0) {
// If queue is empty, tell gulp the task is complete
callback();
}
}
};
return bundle();
};
config.bundleConfigs.forEach(browserifyBundle);
});
In config.js where the first bundleConfig item's entries is a source to a file that has the require() modules, I'd like replace those with module names of modules defined in the package.json browser key.
In the config.js, if I change the bundle configuration to:
bundleConfigs: [
{
entries: ['bootstrap'],
dest: '/dist/js',
outputName: 'shared.js'
}
]
and run the gulp task, it will include bootstrap.js but it doesn't run the shim transformation. jQuery is not being included at all.
This leaves me with a few questions:
Is there a better way to be bundling my js for use in a non-SPA application (ie am I going about this the wrong way)?
If not, is there a way to ensure the shim transformation is run prior to the bundling so that I can have my bundle configuration in one place?
Certainly, you just have to tell your gulp file that it should shim first. Looks like you can add your own shim object when calling browserify from your gulp file. Check out this example
If you want to ensure everything is shimmed before you bundle them, use the deps array: "An array of tasks to be executed and completed before your task will run."
It would look something like this:
gulp.task('shim', function() {
// ...
});
gulp.task('browserify', ['shim'], function(){
// ...
});

Any equivalent gulp plugin for doing "grunt bower"?

With grunt, I could use command grunt bower (provided by grunt-bower-requirejs) to auto-generate RequireJS config file for my local bower components.
Is there any plugin for gulp to perform similar task?
UPDATE: for future readers, please look at the correct answer from #user2326971
Solved it by hook up gulp directly with node module bower-requirejs
npm install bower-requirejs --save-dev
In gulpfile.js
var bowerRequireJS = require('bower-requirejs');
gulp.task('bower', function() {
var options = {
baseUrl: 'src',
config: 'src/app/require.config.js',
transitive: true
};
bowerRequireJS(options, function (rjsConfigFromBower) {
console.log("Updated src/app/require.config.js !");
});
});
Mind that bowerRequireJS is an asynchronous function. So you would need to use a callback (or synchronously return a Promise) to mark that task as asynchronous like so:
gulp.task('bower', function(callback) {
var options = {
baseUrl: 'src',
config: 'src/app/require.config.js',
transitive: true
};
bowerRequireJS(options, function (rjsConfigFromBower) {
callback();
});
});

Categories

Resources