├── .bowerrc
├── .gitignore
├── .jshintrc
├── Gruntfile.js
├── LICENSE
├── README.markdown
├── bower.json
├── build.js
├── package.json
└── src
├── app
├── hello
│ ├── main.js
│ └── main.template.txt
└── world
│ ├── main.js
│ └── main.template.txt
├── common.js
├── hello.html
└── world.html
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "src/app/bower_components"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /app/bower_components/
2 | /build/
3 | /node_modules/
4 | /src/app/bower_components/
5 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "camelcase": true,
3 | "curly": true,
4 | "eqeqeq": true,
5 | "es3": false,
6 | "forin": false,
7 | "immed": true,
8 | "indent": false,
9 | "latedef": "nofunc",
10 | "newcap": true,
11 | "noarg": true,
12 | "noempty": true,
13 | "nonew": true,
14 | "plusplus": false,
15 | "quotmark": true,
16 | "undef": true,
17 | "unused": "vars",
18 | "strict": true,
19 | "trailing": true,
20 |
21 | "boss": false,
22 | "debug": false,
23 | "smarttabs": false,
24 | "eqnull": true,
25 | "laxcomma": true,
26 |
27 | "browser": true,
28 | "devel": true,
29 | "jquery": true,
30 |
31 | "globals": {
32 | "define": false
33 | ,"require": false
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*global module:false*/
2 | module.exports = function(grunt) {
3 | 'use strict';
4 |
5 | // Project configuration.
6 | grunt.initConfig({
7 | // Metadata.
8 | pkg: grunt.file.readJSON('package.json'),
9 | banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
10 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
11 | '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
12 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
13 | ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
14 | // Task configuration.
15 | jshint: {
16 | options: {
17 | jshintrc: '.jshintrc'
18 | },
19 | gruntfile: {
20 | src: 'Gruntfile.js'
21 | },
22 | sourcefiles: {
23 | src: ['src/**/*.js', '!src/app/bower_components/**/*.js']
24 | }
25 | },
26 | requirejs: {
27 | options: {
28 | 'appDir': 'src',
29 | 'dir': 'build',
30 | 'mainConfigFile': 'src/common.js',
31 | 'optimize': 'uglify2',
32 | 'normalizeDirDefines': 'skip',
33 | 'skipDirOptimize': true,
34 | },
35 | centralized: {
36 | options: {
37 | 'modules': [{
38 | 'name': 'common',
39 | 'include': ['jquery',
40 | 'underscore',
41 | 'backbone',
42 | 'text',
43 | 'app/hello/main',
44 | 'app/world/main',
45 | ],
46 | }
47 | ]
48 | }
49 | },
50 | centralizedAlmond: {
51 | options: {
52 | almond: true,
53 | replaceRequireScript: [{
54 | files: ['build/hello.html'],
55 | module: 'common',
56 | modulePath: 'common'
57 | }, {
58 | files: ['build/world.html'],
59 | module: 'common',
60 | modulePath: 'common'
61 | }],
62 | 'modules': [{
63 | 'name': 'common',
64 | 'include': ['jquery',
65 | 'underscore',
66 | 'backbone',
67 | 'text',
68 | 'app/hello/main',
69 | 'app/world/main',
70 | ],
71 | },
72 | ],
73 | }
74 | },
75 | independent: {
76 | options: {
77 | replaceRequireScript: [{
78 | files: ['build/hello.html'],
79 | module: 'app/hello/main',
80 | modulePath: 'app/hello/main'
81 | }, {
82 | files: ['build/world.html'],
83 | module: 'app/world/main',
84 | modulePath: 'app/world/main'
85 | }],
86 | 'modules': [{
87 | name: 'app/hello/main',
88 | include: ['backbone', 'common'],
89 | }, {
90 | name: 'app/world/main',
91 | include: ['backbone', 'common'],
92 | }
93 | ],
94 | }
95 | },
96 | independentAlmond: {
97 | options: {
98 | almond: true,
99 | wrap: true,
100 | replaceRequireScript: [{
101 | files: ['build/hello.html'],
102 | module: 'app/hello/main',
103 | modulePath: 'app/hello/main'
104 | }, {
105 | files: ['build/world.html'],
106 | module: 'app/world/main',
107 | modulePath: 'app/world/main'
108 | }],
109 | 'modules': [{
110 | name: 'app/hello/main',
111 | include: ['backbone'],
112 | insertRequire: ['app/hello/main']
113 | }, {
114 | name: 'app/world/main',
115 | include: ['backbone'],
116 | insertRequire: ['app/world/main']
117 | }
118 | ],
119 | }
120 | },
121 | shared: {
122 | options: {
123 | 'modules': [{
124 | 'name': 'common',
125 | 'include': ['jquery',
126 | 'underscore',
127 | 'backbone',
128 | 'text',
129 | ],
130 | },
131 | {
132 | 'name': 'app/hello/main',
133 | 'exclude': ['common']
134 | },
135 | {
136 | 'name': 'app/world/main',
137 | 'exclude': ['common']
138 | }
139 | ],
140 | }
141 | },
142 | }
143 | });
144 |
145 | // These plugins provide necessary tasks.
146 | grunt.loadNpmTasks('grunt-contrib-jshint');
147 | grunt.loadNpmTasks('grunt-requirejs');
148 |
149 | // Default task.
150 | grunt.registerTask('default', ['jshint']);
151 | };
152 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Cloud Chen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | Requirejs Bundle Types
2 | ===============
3 | > This example project is inspired by [a question from StackOverflow](http://stackoverflow.com/questions/17035609/most-efficient-multipage-requirejs-and-almond-setup)
4 |
5 | ## 3 ways to optimize requirejs bundle files
6 | > 1. Optimize a single JS file for the whole site (w/ or w/o Almond)
7 | 2. Optimize a single JS file for each page (w/ or w/o Almond)
8 | 3. Optimize one JS file for common modules, and then another for each specific page. (Almond doesn't fit in with this way)
9 |
10 | ## Naming them for easier understanding
11 | 1. Centralized / Centralized-Almond
12 | 2. Independent / Independent-Almond
13 | 3. Shared
14 |
15 | ## What does this project have?
16 | _It contains 2 pages, 1 common module, 2 individual modules and corresponding 2 template files_
17 |
18 | ### Folder structure
19 | ```
20 | src
21 | ├── app/
22 | │ ├── bower_components/
23 | │ │ ├── backbone/
24 | │ │ ├── jquery/
25 | │ │ ├── requirejs/
26 | │ │ ├── requirejs-text/
27 | │ │ └── underscore/
28 | │ ├── hello/
29 | │ │ ├── main.js
30 | │ │ └── main.template.txt
31 | │ └── world/
32 | │ ├── main.js
33 | │ └── main.template.txt
34 | ├── common.js
35 | ├── hello.html
36 | └── world.html
37 | ```
38 |
39 | #### 1. Pages
40 | > Including requirejs library and data-main script
41 |
42 | - src/hello.html
43 | - src/world.html
44 |
45 | #### 2. Common module
46 | > including requirejs.config({}) and callback() to launch app
47 |
48 | - src/common.js
49 |
50 | #### 3. Individual modules and corresponding template files
51 | > Individual module and its dependencies
52 |
53 | - src/app/hello/main.js
54 | - src/app/hello/main.template.txt
55 | - src/app/world/main.js
56 | - src/app/world/main.template.txt
57 |
58 | #### 4. Vendor resources
59 | > External static libraries
60 |
61 | _Every library has its own short module/path name in requirejs.config({}) definition_
62 |
63 | _They are installed by [Bower](http://bower.io) which is not important here_
64 | - src/app/bower_components/*
65 |
66 | Building bundle files
67 | ===============
68 |
69 | ### 1. Requirejs native build file or grunt-requirejs task?
70 |
71 | _ | Share common configurations | Almond support | Script tag substitution
72 | ---------------------| :-------------------------: | :------------: | :---------------------:
73 | build file | No | Yes | No
74 | grunt-requirejs task | Yes | Yes | Yes
75 |
76 | > [grunt-requirejs](https://github.com/asciidisco/grunt-requirejs) wins!
77 |
78 | ### 2. Predefined grunt tasks
79 | - `grunt requirejs:centralized` and `grunt requirejs:centralizedAlmond`
80 | - `grunt requirejs:independent` and `grunt requirejs:independentAlmond`
81 | - `grunt requirejs:shared`
82 |
83 | ### 3. Before optimization
84 | #### Every page has 8 requests.
85 |
86 | 
87 |
88 | ### 4. After optimization
89 |
90 | ##### `grunt requirejs:centralized`
91 |
92 | > All modules are bundled into one file
93 |
94 | > Every page shares this bundule file
95 |
96 | > Reduced to 3 requests
97 |
98 | > 
99 |
100 | ##### `grunt requirejs:centralizedAlmond`
101 |
102 | > All modules are bundled into one file (including Almond)
103 |
104 | > Every page shares this bundule file without additional require.js
105 |
106 | > Reduced to 2 requests
107 |
108 | > 
109 |
110 | #### `grunt requirejs:independent`
111 |
112 | > Every individual module is bundle with common modules into its own bundle file
113 |
114 | > Every page loads its own bundule file
115 |
116 | > Reduced to 3 requests
117 |
118 | > 
119 |
120 |
121 | #### `grunt requirejs:independentAlmond`
122 | > Every individual module is bundled with common modules into its own bundle file (including Almond)
123 |
124 | > Every page loads its own bundule file without additional require.js
125 |
126 | > Reduced to 2 requests
127 |
128 | > 
129 |
130 | #### `grunt requirejs:shared`
131 | > Every individual module is bundled into its own bundle file without common modules
132 |
133 | > All common modules are bundled into another file which is shared for all pages
134 |
135 | > Reduced to 4 requests
136 |
137 | > 
138 |
139 | Which one is better?
140 | ===============
141 |
142 | ### It depends on your requirement actually.
143 |
144 | - `grunt requirejs:shared` is most efficient at getting rid of duplicated downloading and utilizing cache as much as possible.
145 | - `grunt requirejs:centralized` is sutiable for small bundle file or mobile site. Download once, use everywhere.
146 | - `grunt requirejs:independent` has least usage scenarios. Might suitable for one-off project.
147 |
148 | Notes
149 | ===============
150 | ## Prefer `paths` rather than `maps` configuration if possible
151 |
152 | It's better to use `paths` to achieve same objective.
153 |
154 | ```
155 | paths: {
156 | 'text': 'requirejs-text/text',
157 | },
158 | ```
159 | Utilizing `paths` rather than `maps` is better for bundle in some cases.
160 | Because Almond doesn't support `maps` configuration.
161 |
162 | ```
163 | map: {
164 | '*': {
165 | 'text': 'requirejs-text/text'
166 | }
167 | },
168 | ```
169 |
170 | ## Write `require.config({})` once, use everywhere
171 |
172 | - Development and build environment share same configuration
173 | - Other environments, for example, test environment can use it as well
174 | - `common.js` is right place to hold it
175 | - **Keep DRY**
176 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "requirejs-bundle-example",
3 | "description": "Typical Requirejs Bundle Examples",
4 | "devDependencies": {
5 | "jquery": "~2.0.3",
6 | "requirejs": "~2.1.8",
7 | "requirejs-text": "~2.0.10",
8 | "backbone": "~1.0.0",
9 | "underscore": "~1.5.1"
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | {
2 | "appDir": "src",
3 | "dir": "build",
4 | "mainConfigFile": "src/common.js",
5 | //"optimize": "uglify2",
6 | "optimize": "none",
7 | //"optimizeCss": "standard",
8 | //"preserveLicenseComments": false,
9 | //"generateSourceMaps": false,
10 | "normalizeDirDefines": "all", //
11 | "skipDirOptimize": false, //speed up non-build bundle
12 | //"skipModuleInsertion": false,
13 | //"stubModules": ["text"],
14 | //"removeCombined": true,
15 | "optimizeAllPluginResources": true,
16 | "modules": [
17 | {
18 | "name": "common",
19 | "include": ["jquery",
20 | "underscore",
21 | "backbone",
22 | "text"
23 | ]
24 | },
25 | {
26 | "name": "app/hello/main",
27 | "exclude": ["common"]
28 | }
29 | ]
30 | }
31 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "requirejs-bundle-examples",
3 | "description": "Typical Requirejs Bundle Examples",
4 | "devDependencies": {
5 | "grunt-contrib-jshint": "~0.6.4",
6 | "grunt": "~0.4.1",
7 | "grunt-requirejs": "git://github.com/cloudchen/grunt-requirejs"
8 | },
9 | "scripts": {
10 | "postinstall": "bower install"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/hello/main.js:
--------------------------------------------------------------------------------
1 | define(function(require){
2 | 'use strict';
3 |
4 | var $ = require('jquery'),
5 | _ = require('underscore'),
6 | template = require('text!./main.template.txt');
7 |
8 | var elm = $('body');
9 | elm.append(template);
10 |
11 | _.each([1,2,3], function(v){
12 | elm.append(v + '
');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/src/app/hello/main.template.txt:
--------------------------------------------------------------------------------
1 |