Using Gulp to build requireJS project - gulp-requi

2019-01-21 08:41发布

问题:

I am trying to use gulp-requirejs to build a demo project. I expect result to be a single file with all js dependencies and template included. Here is my gulpfile.js

var gulp = require('gulp');
var rjs = require('gulp-requirejs');
var paths = {
  scripts: ['app/**/*.js'],
  images: 'app/img/**/*'
};

gulp.task('requirejsBuild', function() {
    rjs({
        name: 'main',
        baseUrl: './app',
        out: 'result.js'
    })
    .pipe(gulp.dest('app/dist'));

});

// The default task (called when you run `gulp` from cli)
gulp.task('default', ['requirejsBuild']);

The above build file works with no error, but the result.js only contains the content of main.js and config.js. All the view files, jquery, underscore, backbone is not included.

How can I configure gulp-requirejs to put every js template into one js file? If it is not the right way to go, can you please suggest other method?

Edit

config.js

require.config({
    paths: {
        "almond": "/bower_components/almond/almond",
        "underscore": "/bower_components/lodash/dist/lodash.underscore",
        "jquery": "/bower_components/jquery/dist/jquery",
        "backbone": "/bower_components/backbone/backbone",
        "text":"/bower_components/requirejs-text/text",
        "book": "./model-book"
    }
});

main.js

// Break out the application running from the configuration definition to
// assist with testing.
require(["config"], function() {
    // Kick off the application.
    require(["app", "router"], function(app, Router) {
        // Define your master router on the application namespace and trigger all
        // navigation from this instance.
        app.router = new Router();

        // Trigger the initial route and enable HTML5 History API support, set the
        // root folder to '/' by default.  Change in app.js.
        Backbone.history.start({ pushState: false, root: '/' });
    });
});

The output is just a combination this two files, which is not what I expected.

回答1:

gulp-requirejs has been blacklisted by the gulp folks. They see the RequireJS optimizer as its own build system, incompatible with gulp. I don't know much about that, but I did find an alternative in amd-optimize that worked for me.

npm install amd-optimize --save-dev

Then in your gulpfile:

var amdOptimize = require('amd-optimize');
var concat = require('gulp-concat');

gulp.task('bundle', function ()
{
    return gulp.src('**/*.js')
        .pipe(amdOptimize('main'))
        .pipe(concat('main-bundle.js'))
        .pipe(gulp.dest('dist'));
});

The output of amdOptimize is a stream which contains the dependencies of the primary module (main in the above example) in an order that resolves correctly when loaded. These files are then concatenated together via concat into a single file main-bundle.js before being written into the dist folder.

You could also minify this file and perform other transformations as needed.


As an aside, in my case I was compiling TypeScript into AMD modules for bundling. Thinking this through further I realized that when bundling everything I don't need the asynchronous loading provided by AMD/RequireJS. I am going to experiment with having TypeScript compile CommonJS modules instead, then bundling them using webpack or browserify, both of which seem to have good support within gulp.



回答2:

UPDATE

My previous answer always reported taskReady even if requirejs reported an error. I reconsidered this approach and added error logging. Also I try to fail the build completely as described here gulp-jshint: How to fail the build? because a silent fail really eats your time. See updated code below.

Drew's comment about blacklist was very helpfull and gulp folks suggest using requirejs directly. So I post my direct requirejs solution:

var DIST = './dist';
var requirejs = require('requirejs');
var requirejsConfig = require('./requireConfig.js').RJSConfig;

gulp.task('requirejs', function (taskReady) {
    requirejsConfig.name = 'index';
    requirejsConfig.out = DIST + 'app.js';
    requirejsConfig.optimize = 'uglify';
    requirejs.optimize(requirejsConfig, function () {
        taskReady();
    }, function (error) {
        console.error('requirejs task failed', JSON.stringify(error))
        process.exit(1);
    });
});

The file at ./dist/app.js is built and uglified. And this way gulp will know when require has finished building. So the task can be used as a dependency.



回答3:

My solution works like this:

./client/js/main.js:

require.config({
    paths: {
        jquery: "../vendor/jquery/dist/jquery",
        ...
    },
    shim: {
        ...
    }
});

define(["jquery"], function($) {
    console.log($);
});

./gulpfile.js:

var gulp = require('gulp'),
    ....
    amdOptimize = require("amd-optimize"),
    concat = require('gulp-concat'),
    ...

gulp.task('scripts', function(cb) {

    var js = gulp.src(path.scripts + '.js')
        .pipe(cached('scripts'))
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(remember('scripts'))
        .pipe(amdOptimize("main",
            {
                name: "main",
                configFile: "./client/js/main.js",
                baseUrl: './client/js'
            }
        ))
        .pipe(concat('main.js'));

        .pipe(gulp.dest(path.destScripts));
}
...

This part was important:

configFile: "./client/js/main.js",
baseUrl: './client/js'

This allowed me to keep my configuration in one place. Otherwise I was having to duplicate my paths and shims into gulpfile.js.



回答4:

This works for me. I seems that one ought to add in uglification etc via gulp if desired. .pipe(uglify()) ...

Currently I have to duplicate the config in main.js to run asynchronously.

    ....

    var amdOptimize = require("amd-optimize");

    ...

    var js = gulp.src(path.scripts + '.js')
        .pipe(cached('scripts'))
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        .pipe(remember('scripts'))
        .pipe(amdOptimize("main",
            {
                name: "main",
                paths: {
                    jquery: "client/vendor/jquery/dist/jquery",
                    jqueryColor: "client/vendor/jquery-color/jquery.color",
                    bootstrap: "client/vendor/bootstrap/dist/js/bootstrap",
                    underscore: "client/vendor/underscore-amd/underscore"
                },
                shim: {
                    jqueryColor : {
                        deps: ["jquery"]
                    },
                    bootstrap: {
                        deps: ["jquery"]
                    },
                    app: {
                        deps: ["bootstrap", "jqueryColor", "jquery"]
                    }
                }
            }

        ))
        .pipe(concat('main.js'));


回答5:

Sorry for my english. This solution works for me. (I used gulp-requirejs at my job)

I think you've forgotten to set mainConfigFile in your gulpfile.js. So, this code will be work

gulp.task('requirejsBuild', function() {
    rjs({
        name: 'main',
        mainConfigFile: 'path_to_config/config.js',
        baseUrl: './app',
        out: 'result.js'
    })
    .pipe(gulp.dest('app/dist'));

});

In addition, I think when you run that task in gulp, require can not find its config file and



回答6:

This is not gulp-requirejs fault.

The reason why only main.js and config.js is in the output is because you're not requiring/defining any other files. Without doing so, the require optimizer wont understand which files to add, the paths in your config-file isn't a way to require them!

For example you could load a main.js file from your config file and in main define all your files (not optimal but just a an example).

In the bottom of your config-file:

// Load the main app module to start the app
requirejs(["main"]); 

The main.js-file: (just adding jquery to show the technique.

define(["jquery"], function($) {}); 

I might also recommend gulp-requirejs-optimize instead, mainly because it adds the minification/obfuscation functions gulp-requirejs lacks: https://github.com/jlouns/gulp-requirejs-optimize

How to implement it:

var requirejsOptimize = require('gulp-requirejs-optimize');

gulp.task('requirejsoptimize', function () {
  return gulp.src('src/js/require.config.js')
    .pipe(requirejsOptimize(function(file) {
      return {
        baseUrl: "src/js",
        mainConfigFile: 'src/js/require.config.js',
        paths: {
          requireLib: "vendor/require/require"
        },
        include: "requireLib",
        name: "require.config",
        out: "dist/js/bundle2.js"
      };
  })).pipe(gulp.dest(''));
});


回答7:

Try this code in your gulpfile:

// Node modules
var
    fs = require('fs'),
    vm = require('vm'),
    merge = require('deeply');    

// Gulp and plugins
var
    gulp = require('gulp'),    
    gulprjs= require('gulp-requirejs-bundler');

// Config
var
    requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('app/config.js') + '; require;'),
    requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
        name: 'main',
        baseUrl: './app',
        out: 'result.js',
        paths: {
            requireLib: 'bower_modules/requirejs/require'
        },
        insertRequire: ['main'],
        // aliases from config.js - libs will be included to result.js
        include: [
            'requireLib',
            "almond",
            "underscore",
            "jquery",
            "backbone",
            "text",
            "book"
        ]
    });

gulp.task('requirejsBuild', ['component-scripts', 'external-scripts'], function (cb) {
    return gulprjs(requireJsOptimizerConfig)            
        .pipe(gulp.dest('app/dist'));
});