I have a project with the following structure:
project
|──css
|──img
|──js
|──app
|──collections
|──models
|──views
|──vendor
|──jquery
|──backbone
|──underscore
|──require
app.js
index.html
Gruntfile.js
package.json
I'm trying to use grunt-contrib-requirejs to build the project into a www folder but I'm not having a lot of luck. The www folder is pretty straight forward - it should look like this:
www
|──css
|──img
|──js
|──optimized.js
index.html
Where optimized.js is the build from the require. It should include everything from the app folder, vendor folder, and app.js
right now my Gruntfile.coffee looks like this:
requirejs:
compile:
options:
mainConfigFile: 'project/js/config.js'
baseUrl: 'project/js'
name: 'app'
include: ['config']
out: 'www/js/optimized.js'
optimize: 'none'
and my config.js file looks like this:
requirejs.config({
baseUrl: 'js',
paths: {
app: 'app',
models: 'app/models',
collections: 'app/collections',
views: 'app/views'
}
});
When I run the grunt task it doesn't give me an error - but the output doesn't include everything from the project/js folder?
Any help would be greatly appreciated!
Thanks!
I dont think the accepted answer is of use. I know its an old question but I ran into the same problems so here is my solution, not for the thread starter but for people in the same situation.
The main problem you probably have is that your require-files are setup in the wrong way. The reason why the grunt job doesnt include all files is most likely because the files aren't properly required or defined. It has nothing todo with the grunt job.
It's not enough to have a config file (app.js in your case), you also need to require the files. For example you can do that in a main.js file:
require(["global","highcharts-chartdata"], function () {});
Please have a look at my setup that works. This is the folder structure:
Project
|
├───dist
| ├───css
| | bundle.css
| ├───fonts
| ├───images
| └───js
| bundle.js
| index.html
|
└───src
├───js
│ └───vendor
│ ├───bootstrap
│ ├───highcharts
│ ├───jquery
│ └───require
| require.js
| charts.js
| global.js
| main.js
| require.config.js
└───less
├───bootstrap
│ └───mixins
├───bootstrap_overrides
└───font-awesome
gruntfile.js
This is my gruntfile:
module.exports = function(grunt) {
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
jshint: {
files: ['src/js/*.js'],
options: {
globals: {
$: false,
console: true,
module: true,
document: true
}
}
},
less: {
compile: {
options: {
paths: ['src/less'],
plugins: [
new (require('less-plugin-autoprefix'))({browsers: ["last 2 versions"]}),
new (require('less-plugin-clean-css'))
]
},
files: {
'dist/css/bundle.css': 'src/less/style.less'
}
}
},
requirejs: {
compile: {
options: {
baseUrl: "src/js",
mainConfigFile: 'src/js/require.config.js',
paths: {
requireLib: "vendor/require/require"
},
include: "requireLib",
name: "require.config",
out: "dist/js/bundle.js"
}
}
},
watch: {
files: ['src/js/*.js','src/less/**/*.less'],
tasks: ['jshint','less','requirejs']
}
});
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-requirejs');
// Default task(s).
grunt.registerTask('default', ['jshint','less','requirejs']);
};
This is the require.config-file:
requirejs.config({
baseUrl: 'js',
paths: {
"jquery": "vendor/jquery/jquery",
"jquery-ui": "vendor/jquery/jquery-ui",
"bootstrap-collapse": "vendor/bootstrap/collapse",
"bootstrap-transition": "vendor/bootstrap/transition",
"highcharts": "vendor/highcharts/highcharts-4.1.4.min",
"highcharts-chartdata": "charts"
},
shim: {
"bootstrap": ["jquery"],
"jquery-ui": ["jquery"],
"bootstrap-collapse": ["jquery"],
"bootstrap-transition": ["jquery"],
"highcharts" : ["jquery"],
"highcharts-chartdata" : ["highcharts"]
}
});
// Load the main app module to start the app
requirejs(["main"]);
Please observe that the line above requirejs(["main"]); is actually "loading" the code in my main.js-file (below) which in its turn is loading other files:
require(["global","highcharts-chartdata"], function () {});
Without those, grunt-contrib-requirejs wont know what to include.
In our case we want to output a single js-file (optimized.js) to be included in your start page (index.html). For this to work I want point out that we need to add the require.js-script as well, without it the console would just say require is not defined.
To do that you just add the following rows in your gruntfile:
paths: {
requireLib: "vendor/require/require"
},
include: "requireLib",
You can read about it here: http://requirejs.org/docs/optimization.html#onejs
Try putting in appDir and dir properties in the grunt-contrib-requirejs config.
For more details on the proprties, please refer to example.build.js in https://github.com/jrburke/r.js/blob/master/build/example.build.js
Try it with the option preserveLicenseComments: false. The license comments in bower.js start with '//' and somehow requirejs skips the whole file then
Related
This is my project structure:
Project
|-module1
| |-package.json
| |-gulpfile.babel.js
|-module2
| |-package.json
| |-gulpfile.babel.js
|-package.json
|-scripts.js
|-babel.config.js
As you see in root of the project I have scripts.js that exports some things. After reading all the information about Babel7 configuration here in the root of the project I created babel.config.js with the following content:
module.exports = {
presets: [
['#babel/env', {
targets: {
node: 'current',
firefox: '60',
chrome: '67',
safari: '11.1',
},
}],
],
};
As I understand I don't need to create .babelrc in module1 and module2 as I have a babel.config.js in the root. However, when I run gulp on module1 I see that gulp doesn't find the configuration for babel as I get:
Project/module1/gulpfile.babel.js:26
import gulp from 'gulp';
^^^^
SyntaxError: Unexpected identifier
Where is my mistake?
The only solution I found is the following - we should use gulpfile.js instead of gulpfile.babel.js and config babel manually. I mean:
in Project/module1/gulpfile.js
require('#babel/register')({
configFile: './../babel.config.js',
ignore: [/node_modules/]
})
require('./tasks')
and in Project/module1/tasks.js we put all gulp tasks.
I have a file structure like this:
/server/
- package.json
- node_modules/
- Gruntfile.js
/public/
- index.html
- assets/
When in /server I run npm install, which downloads things like Angular into /server/node_modules.
I then run the Gruntfile.js which looks like this:
require('load-grunt-tasks')(grunt);
grunt.initConfig({
//concat js
concat: {
options: {
separator: ';',
sourceMap: true
},
lib: {
src: [
'./node_modules/angular/angular.js',
'./node_modules/angular-route/angular-route.js',
'./node_modules/angular-animate/angular-animate.js'
],
dest: '../public/assets/build/lib/lib.min.js'
}
},
//minify js
uglify: {
options: {
mange: true,
compress: true,
sourceMap: true
},
lib: {
src: '<%= concat.lib.dest %>',
dest: '<%= concat.lib.dest %>'
}
}
});
grunt.registerTask('build', ['concat', 'uglify']);
The grunt file works as expected to concat and minify the Angular modules with a source map. The problem is that the domain name points to the public directory, but the source map wants to point to the Angular source code in the server directory, which I don't think will work.
How do I get around this problem? Do I have to have the node_modules in the root of the public directory? I'd rather not have any precompiled code in the public directory if possible, the reason being that when I put the site live, I can simply FTP the public directory and ignore the server, reducing unnecessary bulk.
I have a Typescript project:
myproject
|
+-src (folder)
| |
| +-main.ts
| +-stringHandler.ts
| +-disposable.ts
+-out (folder)
| |
| +-...
+-Gruntfile.js
In my Grunt configuration I have a 2-step task which compiles all .ts files in myproject/src/ and generates corresponding .js files into myproject/out/. So after the first step of the task is complete, I have the following:
myproject
|
+-out (folder)
|
+-main.js
+-stringHandler.js
+-disposable.js
Bundling
The second step of the task is generating bundle file myproject.js. I am using RequireJS for this purpose.
I have installed grunt-contrib-requirejs. The Gruntfile.js file handling the bundling task is as follows (showing only relevant parts in the file):
module.exports = function(grunt) {
var config = {
pkg: grunt.file.readJSON('package.json'),
requirejs: {
compile: {
options: {
baseUrl: "out",
bundles: {
'myproject': ['main', 'stringHandler', 'disposable']
},
out: 'out/myproject.js'
}
}
}
};
grunt.initConfig(config);
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.registerTask('default', ['compile', 'requirejs']);
};
When Grunt reaches requirejs, after successfully compiling the project, I get the following error:
Running "requirejs:compile" (requirejs) task { [Error: Error: Missing
either a "name", "include" or "modules" option
at Function.build.createConfig (C:\Users\myuser\Documents\myproject\node_modules\grunt-contrib-requirejs\node_modules\requirejs\bin\r.js:29567:19)
] originalError: [Error: Missing either a "name", "include" or
"modules" option] }
I can understand there are missing parameters, but when I use name I get other errors. I guess there must be something wrong at a more generic level. What is the correct configuration format? Thanks
This assumes main.ts is your application's entry point and that it contains a require.config section with your application dependencies (libraries and shims).
First, move the require.config section out of main.ts and into its own file, config.ts. Leave the application bootstrap code in main.ts.
Then determine where you want this optimized application code deployed. Let's assume it is to a directory named build, which is parallel to your src and out folders.
Update you Gruntfile to reflect this configuration:
requirejs: {
compile: {
options: {
baseUrl: "out",
mainConfigFile: "out/config.js",
modules: [
{ name: "main" }
],
dir: "build",
optimize: "none" // skip compression while debugging
}
}
}
You can read more about each of these config options at http://requirejs.org/ but here's the basic rundown:
baseUrl: Where the source JS code lives.
mainConfigFile: Points to the config object mentioned above. It tells the plugin where the dependencies live. This obviates the need to specify and manually update the list of dependencies in two places.
modules: Is an array of application bootstraps. In this case a list of one, main.js.
dir: Where the optimized application will be generated. Note that your dependencies will also be copied here.
optimize: I left this off so you can easily debug the resulting app under ./build. Remove it when you're happy and the plugin will optimize (compress and munge) your build files.
When following the general setup of example-multipage provided in the docs the common.js module seems to cause dependencies to make async XMLHttpRequest calls.
my directory structure is:
|-static
|-core
|-js
|-myApp.js
|-require.js
|-common.js
|-app.build.js
|-app
|-myApp.js
|-vendor
|-js
|-jquery.js
|-bootstrap.js
|-fancybox.js
contents of common.js:
require.config({
baseUrl: "/static/core/js",
paths: {
'jquery':'../../vendor/jquery/1.7.2/jquery',
'bootstrap':'../../vendor/bootstrap/2.2.2/js/bootstrap',
'fancybox':'../../vendor/fancybox/2.0.6/jquery.fancybox',
},
shim: {
'bootstrap':['jquery'],
'fancybox': ['jquery'],
'app/messages': ["jquery"],
},
waitSeconds: 12
});
contents of myApp.js
require(['common'], function (common) {
require(['app/myApp']);
});
Contents of app/myApp.js (YES I KNOW I AM POLLUTING THE GLOBAL NAMESPACE):
define(function (require) {
var $ = require('jquery');
require('fancybox');
require('app/messages');
//all my code here
});
My modules are defined as follows in app.build.js:
mainConfigFile: 'common.js',
removeCombined: true,
modules: [
{
name: 'common',
include: ['jquery', 'bootstrap']
},
{
name: 'myApp',
include: ['app/myApp'],
exclude: ['common']
},
],
When i REMOVE the common module from the build, everything works fine. I get one myApp.js file with all the dependencies combined into the one file (perfect!).
When i ADD the common module back in, the resulting js files are loaded: common.js(combined), myApp.js(combined), PLUS I ALSO GET myApp.js, common.js, bootstrap.js, fancybox.js, messages.js and nothing works.
One guess is that because i am creating paths to actual .js files in the require.config it is loading them as dependencies. Where if i only defined paths to directories this would not occur?
UPDATE:
Since my common.js is shimmed, looks like i need to follow example-multipage-shim.
Getting closer.
I'm having issues getting Grunt to perform requirejs optimization on a project with the following structure:
static/js
|── apps
|── app.js
|── dash.js
|── news.js
... (many more 'app' files)
|── build
|── collections
|── libs
|── models
|── util
|── views
Each of static/js/apps/*.js should be compiled to static/js/build/*.js containing the relevant dependencies (eg. views/view1, libs/query etc).
This is currently being performed by a basic bash script:
JS_ROOT="static/js"
for f in ${JS_ROOT}/apps/*
do
FILE=$(basename -s .js ${f})
pushd .
cd ${JS_ROOT} && r.js -o baseUrl=. name=libs/require-min.js include=apps/${FILE} out=build/${FILE}.js
popd
done
I'm attempting to move to a Grunt-based optimization, with the following in Grunt.js:
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: './apps/',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}
Running generates the following error:
>> Tracing dependencies for: app
>> Error: ENOENT, no such file or directory
>> 'static/js/build/apps/libs/jquery.js'
>> In module tree:
>> app
I can clearly see what the problem is, but am failing to figure out how to indicate that the dependencies in each static/js/apps/*.js file are in static/js/ not static/js/build
In addition to this, I'm assuming that the modules block containing name: 'app' should be outputting the compiled file static/js/build/app.js from the contents of static/js/apps/app.js.
Without creating an additional module block for each file in static/js/apps, how can I compile each of the files into their relevant static/js/build/*.js file?
Update 1
So the following in my Gruntfile compiles static/js/apps/app.js successfully into static/js/build/app.js:
requirejs: {
compile: {
options: {
baseUrl: 'static/js/',
include: './apps/app.js',
out: 'static/js/build/app.js',
}
}
}
The next step being to compile static/js/apps/*.js into static/js/build/*.js without having to define each individually...
Update 2
Modifying the above to:
requirejs: {
compile: {
options: {
baseUrl: '../',
include: './apps/<%= appFile %>',
out: 'static/js/build/<%= appFile %>',
}
}
}
And creating the task:
grunt.registerTask('buildrjs', function() {
var dir='static/js/apps/';
grunt.file.setBase(dir);
var files = grunt.file.expand(['*.js']);
files.forEach(function(filename) {
grunt.log.write('Compiling '+filename+'\n');
grunt.config.set('appFile', filename);
grunt.task.run('requirejs:compile');
});
});
Almost gets me to the solution. The tasks runs through each file in static/js/apps/ and passes the filename into grunt.config.set('appFile', filename);. The output of the task outputs Compiling app.js Compiling news.js... etc, however afterwards the actual requirejs:compile tasks runs over & over on the last file in the static/js/apps/ directory, rather than each individual file. An async issue?
Solved, by passing multiple sets of options to the requirejs task, thanks to this article for the final pointers I needed:
module.exports = function(grunt) {
var files = grunt.file.expand('static/js/apps/*.js');
var requirejsOptions = {};
files.forEach(function(file) {
var filename = file.split('/').pop();
requirejsOptions[filename] = {
options: {
baseUrl: 'static/js/',
include: './apps/'+filename,
out: 'static/js/build/'+filename
}
};
});
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
requirejs: requirejsOptions,
});
};
Then the ['requirejs'] task can be run as normal and will output the appropriate compiled .js file as per each of the options: {} blocks that were specified in requirejsOptions, eg:
grunt.registerTask('default', ['requirejs']);
You need to change baseUrl to static/js from apps in requirejs build config. As currently baseUrl is pointing to apps directory, require is trying to search dependency files in apps directory. If you change the baseUrl to static/js it will find those dependency files.
requirejs: {
compile: {
options: {
appDir: 'static/js/',
baseUrl: 'static/js',
dir: 'static/js/build/',
modules: [
{
name: 'app',
}
]
}
}
}