├── .meteor
├── packages
├── .gitignore
├── platforms
└── .id
├── test
├── .meteor
│ ├── .gitignore
│ ├── release
│ ├── platforms
│ ├── .finished-upgraders
│ ├── .id
│ ├── packages
│ └── versions
├── packages
│ └── numtel:lazy-bundles
├── public
│ ├── mockup.less
│ ├── globber
│ │ └── anything.js
│ ├── mockup.coffee
│ └── mockup.html
├── private
│ ├── mockup.less
│ ├── mockup.coffee
│ └── mockup.html
├── test-glob.publicbundles.json
├── test.privatebundles.json
├── test.publicbundles.json
├── ci.sh
├── test-minified.publicbundles.json
└── server
│ ├── router.js
│ └── index.js
├── .gitignore
├── .versions
├── .travis.yml
├── package.js
├── private-bundle-plugin.js
├── LICENSE
├── README.md
└── plugin
└── compile-bundles.js
/.meteor/packages:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/test/.meteor/.gitignore:
--------------------------------------------------------------------------------
1 | local
2 |
--------------------------------------------------------------------------------
/test/packages/numtel:lazy-bundles:
--------------------------------------------------------------------------------
1 | ../..
--------------------------------------------------------------------------------
/.meteor/platforms:
--------------------------------------------------------------------------------
1 | browser
2 | server
3 |
--------------------------------------------------------------------------------
/test/.meteor/release:
--------------------------------------------------------------------------------
1 | METEOR@1.1.0.2
2 |
--------------------------------------------------------------------------------
/test/.meteor/platforms:
--------------------------------------------------------------------------------
1 | server
2 | browser
3 |
--------------------------------------------------------------------------------
/test/public/mockup.less:
--------------------------------------------------------------------------------
1 | h1.horses { color: red; }
2 |
--------------------------------------------------------------------------------
/test/private/mockup.less:
--------------------------------------------------------------------------------
1 | h1.cheese { color: orange; }
2 |
--------------------------------------------------------------------------------
/test/public/globber/anything.js:
--------------------------------------------------------------------------------
1 | console.log('something');
2 |
--------------------------------------------------------------------------------
/test/public/mockup.coffee:
--------------------------------------------------------------------------------
1 | tester = ->
2 | console.log 'horses'
3 |
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.*~
2 | *.swp
3 | *.swo
4 | settings.json
5 | .build*
6 | .npm
7 |
--------------------------------------------------------------------------------
/.versions:
--------------------------------------------------------------------------------
1 | meteor@1.1.6
2 | numtel:lazy-bundles@1.0.1
3 | underscore@1.0.3
4 |
--------------------------------------------------------------------------------
/test/private/mockup.coffee:
--------------------------------------------------------------------------------
1 | tester = ->
2 | console.log 'cheese'
3 |
4 |
--------------------------------------------------------------------------------
/test/test-glob.publicbundles.json:
--------------------------------------------------------------------------------
1 | {
2 | "public-glob-test": [
3 | "globber/*.js"
4 | ]
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/test/private/mockup.html:
--------------------------------------------------------------------------------
1 |
2 | Hey everybody!
3 |
4 |
--------------------------------------------------------------------------------
/test/public/mockup.html:
--------------------------------------------------------------------------------
1 |
2 | Hey everybody!
3 |
4 |
--------------------------------------------------------------------------------
/test/test.privatebundles.json:
--------------------------------------------------------------------------------
1 | {
2 | "private-bundle-test": [
3 | "mockup.html",
4 | "mockup.less",
5 | "mockup.coffee"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/test/test.publicbundles.json:
--------------------------------------------------------------------------------
1 | {
2 | "public-bundle-test": [
3 | "mockup.html",
4 | "mockup.less",
5 | "mockup.coffee"
6 | ]
7 | }
8 |
--------------------------------------------------------------------------------
/test/ci.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cd ${0%/*}
3 | if (RUN_ONCE=1 meteor | tee /dev/tty | grep -q "All tests pass!")
4 | then
5 | exit 0
6 | else
7 | exit 1
8 | fi
9 |
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | language: node_js
3 | node_js:
4 | - "0.10"
5 | before_install:
6 | - "curl https://install.meteor.com/ | /bin/sh"
7 | script:
8 | - "./test/ci.sh"
9 |
--------------------------------------------------------------------------------
/test/test-minified.publicbundles.json:
--------------------------------------------------------------------------------
1 | {
2 | "#settings": {
3 | "minify": true
4 | },
5 | "public-minified-test": [
6 | "mockup.html",
7 | "mockup.less",
8 | "mockup.coffee"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/test/.meteor/.finished-upgraders:
--------------------------------------------------------------------------------
1 | # This file contains information which helps Meteor properly upgrade your
2 | # app when you run 'meteor update'. You should check it into version control
3 | # with your project.
4 |
5 | notices-for-0.9.0
6 | notices-for-0.9.1
7 | 0.9.4-platform-file
8 | notices-for-facebook-graph-api-2
9 |
--------------------------------------------------------------------------------
/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | itx4ee1x4ps6a1t8f278
8 |
--------------------------------------------------------------------------------
/test/.meteor/.id:
--------------------------------------------------------------------------------
1 | # This file contains a token that is unique to your project.
2 | # Check it into your repository along with the rest of this directory.
3 | # It can be used for purposes such as:
4 | # - ensuring you don't accidentally deploy one app on top of another
5 | # - providing package authors with aggregated statistics
6 |
7 | uui3efui6yzqrvpp9x
8 |
--------------------------------------------------------------------------------
/test/.meteor/packages:
--------------------------------------------------------------------------------
1 | # Meteor packages used by this project, one per line.
2 | # Check this file (and the other files in this directory) into your repository.
3 | #
4 | # 'meteor add' and 'meteor remove' will edit this file for you,
5 | # but you can also edit it by hand.
6 |
7 | meteor-platform
8 | autopublish
9 | insecure
10 | less
11 | coffeescript
12 | numtel:lazy-bundles
13 | iron:router
14 | http
15 | nooitaf:colors
16 |
--------------------------------------------------------------------------------
/package.js:
--------------------------------------------------------------------------------
1 | Package.describe({
2 | name: 'numtel:lazy-bundles',
3 | summary: 'Create bundles for lazy-loading components, optionally with authentication',
4 | version: '1.0.1',
5 | git: 'https://github.com/numtel/meteor-lazy-bundles.git'
6 | });
7 |
8 | Package.registerBuildPlugin({
9 | name: 'compileBundles',
10 | use: [ 'underscore@1.0.3' ],
11 | sources: [
12 | 'plugin/compile-bundles.js'
13 | ],
14 | npmDependencies: {
15 | 'glob': '5.0.10'
16 | }
17 | });
18 |
19 | Package.onUse(function(api){
20 | api.versionsFrom('1.0.2.1');
21 | api.addFiles('private-bundle-plugin.js', 'server');
22 | api.export('registerIRPrivateBundles', 'server');
23 | });
24 |
--------------------------------------------------------------------------------
/test/server/router.js:
--------------------------------------------------------------------------------
1 |
2 | // iron:router plugin must be installed
3 | registerIRPrivateBundles();
4 |
5 | // Initialize iron:router Plugin on server-side
6 | Router.plugin('privateBundles', {
7 | // Optional: Set to true to output file load errors to console
8 | debug: true,
9 | // Optional: Route path (without leading slash), Default '_loadSource'
10 | route: 'authBundle',
11 | // Optional: Determine if a route should serve the file requested.
12 | // If not specified, all requests will be granted.
13 | // ALL requests granted means that your private directory would
14 | // not be private any more!
15 | // @context - Same as Router.route context
16 | // @param {string} path - Filename requested
17 | // @return boolean - true to serve file, false to serve nothing
18 | allow: function(path){
19 | // Sample authentication scheme
20 | // Require query parameter 'allow' to have value 'yes'
21 | return this.params.query.allow === 'yes';
22 | }
23 | });
24 |
--------------------------------------------------------------------------------
/test/.meteor/versions:
--------------------------------------------------------------------------------
1 | autopublish@1.0.3
2 | autoupdate@1.2.1
3 | base64@1.0.3
4 | binary-heap@1.0.3
5 | blaze@2.1.2
6 | blaze-tools@1.0.3
7 | boilerplate-generator@1.0.3
8 | callback-hook@1.0.3
9 | check@1.0.5
10 | coffeescript@1.0.6
11 | ddp@1.1.0
12 | deps@1.0.7
13 | ejson@1.0.6
14 | fastclick@1.0.3
15 | geojson-utils@1.0.3
16 | html-tools@1.0.4
17 | htmljs@1.0.4
18 | http@1.1.0
19 | id-map@1.0.3
20 | insecure@1.0.3
21 | iron:controller@1.0.7
22 | iron:core@1.0.7
23 | iron:dynamic-template@1.0.7
24 | iron:layout@1.0.7
25 | iron:location@1.0.7
26 | iron:middleware-stack@1.0.7
27 | iron:router@1.0.7
28 | iron:url@1.0.7
29 | jquery@1.11.3_2
30 | json@1.0.3
31 | launch-screen@1.0.2
32 | less@1.0.14
33 | livedata@1.0.13
34 | logging@1.0.7
35 | meteor@1.1.6
36 | meteor-platform@1.2.2
37 | minifiers@1.1.5
38 | minimongo@1.0.8
39 | mobile-status-bar@1.0.3
40 | mongo@1.1.0
41 | nooitaf:colors@0.0.2
42 | numtel:lazy-bundles@1.0.1
43 | observe-sequence@1.0.6
44 | ordered-dict@1.0.3
45 | random@1.0.3
46 | reactive-dict@1.1.0
47 | reactive-var@1.0.5
48 | reload@1.1.3
49 | retry@1.0.3
50 | routepolicy@1.0.5
51 | session@1.1.0
52 | spacebars@1.0.6
53 | spacebars-compiler@1.0.6
54 | templating@1.1.1
55 | tracker@1.0.7
56 | ui@1.0.6
57 | underscore@1.0.3
58 | url@1.0.4
59 | webapp@1.2.0
60 | webapp-hashing@1.0.3
61 |
--------------------------------------------------------------------------------
/private-bundle-plugin.js:
--------------------------------------------------------------------------------
1 | // numtel:lazy-bundles
2 | // MIT License, ben@latenightsketches.com
3 | var path = Npm.require('path');
4 | var fs = Npm.require('fs');
5 |
6 | var BASE_DIR = 'assets/app';
7 |
8 | // Provide iron:router plugin for loading private bundles with an
9 | // authentication lamdba function
10 | // Call this function to install the 'privateBundles' plugin
11 | // Not installed by default, just in case a different router is used.
12 | registerIRPrivateBundles = function() {
13 | Iron.Router.plugins.privateBundles = function (router, options) {
14 | options = options || {};
15 | var route = '/' + (options.route || '_loadSource');
16 | router.route(route, function(){
17 | var query = this.params.query;
18 | var filename = path.join(BASE_DIR, query.f);
19 | if(filename.substr(0, BASE_DIR.length) !== BASE_DIR){
20 | // Security breach trying to access file outside of BASE_DIR
21 | this.response.end();
22 | }else if(options.allow && !options.allow.call(this, query.f)){
23 | this.response.end();
24 | }else{
25 | fs.readFile(filename, function(err, data){
26 | if(err){
27 | options.debug && console.log(err);
28 | this.response.end();
29 | }else{
30 | this.response.end(data);
31 | }
32 | }.bind(this));
33 | }
34 | }, { where: 'server' });
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 ben@latenightsketches.com
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
24 | Copyright © Maxime QUANDALLE
25 |
26 | Permission is hereby granted, free of charge, to any person obtaining a copy of
27 | this software and associated documentation files (the "Software"), to deal in
28 | the Software without restriction, including without limitation the rights to
29 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
30 | of the Software, and to permit persons to whom the Software is furnished to do
31 | so, subject to the following conditions:
32 |
33 | The above copyright notice and this permission notice shall be included in all
34 | copies or substantial portions of the Software.
35 |
36 | The Software is provided "as is", without warranty of any kind, express or
37 | implied, including but not limited to the warranties of merchantability, fitness
38 | for a particular purpose and noninfringement. In no event shall the authors or
39 | copyright holders be liable for any claim, damages or other liability, whether
40 | in an action of contract, tort or otherwise, arising from, out of or in
41 | connection with the software or the use or other dealings in the Software
42 |
--------------------------------------------------------------------------------
/test/server/index.js:
--------------------------------------------------------------------------------
1 | var cases = {
2 | 'public-bundle-test.js': [
3 | /class="horses"/, // From public/mockup.html
4 | /console.log\('horses'\)/, // From compiled version of public/mockup.coffee
5 | ],
6 | 'public-bundle-test.css': [
7 | /color: red/, // From compiled version of public/mockup.less
8 | ],
9 | 'authBundle?allow=yes&f=private-bundle-test.js': [
10 | /class="cheese"/, // From private/mockup.html
11 | /console.log\('cheese'\)/, // From compiled version of private/mockup.coffee
12 | ],
13 | 'authBundle?allow=yes&f=private-bundle-test.css': [
14 | /color: orange/, // From compiled version of private/mockup.less
15 | ],
16 | 'public-minified-test.js': [
17 | // Check for contents without newlines
18 | /function\(\)\{return HTML.Raw\('/,
19 | /class="horses"/,
20 | /function\(\)\{return console.log\("horses"\)\}\}/
21 | ],
22 | 'public-minified-test.css': [
23 | // Check for contents without newlines
24 | /h1.horses\{color:red\}/
25 | ],
26 | 'public-glob-test.js': [
27 | /console.log\('something'\)/, // From public/globber/anything.js
28 | ]
29 | };
30 |
31 | function performTests() {
32 | var allStatus = [];
33 | for(var file in cases) {
34 | try {
35 | var content = HTTP.get(Meteor.absoluteUrl(file)).content;
36 | } catch (err) {
37 | throw new Meteor.error(500, err);
38 | }
39 | var caseStatus = {
40 | file: file,
41 | passed: 0,
42 | count: cases[file].length,
43 | result: null
44 | };
45 |
46 | for(var i = 0; i < cases[file].length; i++) {
47 | if(content.match(cases[file][i]) !== null) {
48 | caseStatus.passed++;
49 | }
50 | }
51 |
52 | caseStatus.result = caseStatus.passed === caseStatus.count ? 'pass' : 'fail';
53 |
54 | allStatus.push(caseStatus);
55 | }
56 |
57 | return allStatus;
58 | }
59 |
60 | Meteor.startup(function() {
61 | // Give a few seconds for the server to be ready
62 | Meteor.setTimeout(function() {
63 | var allPass = true;
64 |
65 | performTests().forEach(function(result) {
66 | console.log(result.file.bold);
67 | if(result.result === 'pass') {
68 | console.log((result.count + ' Passed!').green);
69 | } else {
70 | allPass = false;
71 | console.log((result.passed + ' / ' + result.count + ' passed').red);
72 | }
73 | });
74 |
75 | console.log(('\n' + (allPass ? 'All tests pass!' : 'Test Failure')).bold);
76 |
77 | if('RUN_ONCE' in process.env) {
78 | Meteor.setTimeout(function() {
79 | process.kill(process.env.METEOR_PARENT_PID, 'SIGINT');
80 | }, 1000);
81 | }
82 |
83 | }, 1000);
84 | });
85 |
86 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # numtel:lazy-bundles [](https://travis-ci.org/numtel/meteor-lazy-bundles)
2 |
3 | By default, Meteor does not perform any special handling on files placed inside the `public` and `private` directories of your application.
4 |
5 | With this package, you can place `xxx.publicbundles.json` or `xxx.privatebundles.json` files in your application directory with a description of bundles of source files to process for client-side lazy-loading.
6 |
7 | Source files will be transpiled and collected into a single `.js` and `.css` file for each bundle.
8 |
9 | > This package supersedes [`numtel:publicsources`](https://github.com/numtel/meteor-publicsources) and [`numtel:privatesources`](https://github.com/numtel/meteor-privatesources).
10 |
11 | ## Installation
12 |
13 | ```
14 | meteor add numtel:lazy-bundles
15 | ```
16 |
17 | ## Public Bundle Descriptions
18 |
19 | Inside of a `xxx.publicbundles.json` file in the root of your application, you may describe bundles of source files to serve to the client. The filename may be different than `xxx.publicbundles.json` as long as it includes the extension `.publicbundles.json`. (e.g. `myapp.publicbundles.json` is also valid)
20 |
21 | Filenames specified inside of each bundle are relative to the application's `public` directory.
22 |
23 | The following example will serve `admin.js`, `admin.js.map`, `admin.css`, and `admin.css.map`:
24 |
25 | ```javascript
26 | {
27 | "admin": [
28 | "admin/templates.html",
29 | "admin/styles.less",
30 | "admin/main.coffee"
31 | ]
32 | }
33 | ```
34 |
35 | * Listed filenames may be glob patterns in order to include multiple files without manually specifying each filename, as defined by [`glob` NPM package](https://github.com/isaacs/node-glob). See [`test/test-glob.publicbundles.json`](test/test-glob.publicbundles.json) for an example using a glob.
36 | * Bundle names may contain slashes to simulate a directory path
37 | * `.html` files are automatically sorted to the beginning of a bundle but other template filetypes are not. Be sure to include template files like `.jade` first in the bundle so that subsequent scripts will have access to apply helpers, events and handlers.
38 |
39 | ## Private Bundle Descriptions
40 |
41 | Private bundles may be specified exactly the same as public bundles except with the `.privatebundles.json` extension.
42 |
43 | Filenames specified inside of each private bundle are relative to the application's `private` directory.
44 |
45 | To obtain asset data directly from your application's server code, you may use the built-in method, `Assets.getText()`. Otherwise, load the files using the provided `iron:router` plugin described below.
46 |
47 | ## Minified Output
48 |
49 | For production output, bundles may be minified using the available setting.
50 |
51 | See [`test/test-minified.publicbundles.json`](test/test-minified.publicbundles.json) for a minified bundle example.
52 |
53 | ## Iron Router integration
54 |
55 | Combine with the [`miro:preloader` package](https://github.com/MiroHibler/meteor-preloader) to dynamically load the bundled `.js` and `.css` files when browsing to a route
56 |
57 | ```javascript
58 | // Route example using miro:preloader
59 | Router.route('/', function () {
60 | this.render('hello');
61 | }, {
62 | controller: 'PreloadController',
63 | preload: {
64 | styles: 'hello.css',
65 | sync: 'hello.js'
66 | }
67 | });
68 | ```
69 |
70 | ### Private bundle authentication plugin
71 |
72 | Private bundles can be loaded on the client using the provided `iron:router` plugin.
73 |
74 | See [`test/server/router.js`](test/server/router.js) for an example of how to configure the authentication plugin.
75 |
76 | ## Notes
77 |
78 | * If adding a new source handler package (e.g. `mquandalle:jade`), you must restart Meteor for this package to recognize the change.
79 | * If using a glob, Meteor must be restarted to search for new/deleted files.
80 |
81 | ## Test application
82 |
83 | Test cases for this package are not executed using the normal `meteor test-packages` command. Instead, start the Meteor app inside of the `test` directory and see the results in the console.
84 |
85 | ```bash
86 | $ git clone https://github.com/numtel/meteor-lazy-bundles
87 |
88 | $ cd meteor-lazy-bundles/test
89 |
90 | # Test results will be output to the console
91 | $ meteor
92 | ```
93 |
94 | Test cases are described in [`test/server/index.js`](test/server/index.js).
95 |
96 | ## License
97 |
98 | MIT
99 |
100 | Portions copyright Maxime Quandalle @mquandalle
101 |
--------------------------------------------------------------------------------
/plugin/compile-bundles.js:
--------------------------------------------------------------------------------
1 | // numtel:lazy-bundles
2 | // MIT License, ben@latenightsketches.com
3 |
4 | var fs = Npm.require('fs');
5 | var path = Npm.require('path');
6 | var glob = Npm.require('glob');
7 |
8 | // With the NPM dependency (glob), cannot simply require files from
9 | // meteor/tools directory because the Npm.require root directory has changed
10 | var toolDir = path.dirname(process.mainModule.filename);
11 | // Assume never more than 100 directories deep
12 | var rootRelPath = _.range(100).map(function() { return '..' }).join('/');
13 | // Determine meteor/tools relative directory path
14 | var relToolDir = path.join(rootRelPath, toolDir);
15 |
16 | function requireMeteorTool(file) {
17 | return Npm.require(path.join(relToolDir, file + '.js'))
18 | }
19 |
20 | // Load required meteor build tools
21 | var compiler = requireMeteorTool('compiler');
22 | var isopackets = requireMeteorTool('isopackets');
23 | var projectContextModule = requireMeteorTool('project-context');
24 | var PackageSource = requireMeteorTool('package-source');
25 |
26 | // Obtain array of loaded packages to make build plugins available to bundles
27 | var loadedPackages = [];
28 | if(process.publicsourcesProjectContext){
29 | var projectContext = process.publicsourcesProjectContext;
30 | }else{
31 | var projectContext = new projectContextModule.ProjectContext({
32 | projectDir: process.cwd()
33 | });
34 | process.publicsourcesProjectContext = projectContext;
35 | projectContext.prepareProjectForBuild();
36 | }
37 | if(projectContext.isopackCache !== null) {
38 | for(var packageName in projectContext.isopackCache._isopacks){
39 | loadedPackages.push(packageName);
40 | }
41 | }
42 |
43 | // Begin code borrowed from mquandalle:bower/plugin/handler.js
44 | function loadJSONContent(compileStep, content) {
45 | try {
46 | return JSON.parse(content);
47 | } catch (e) {
48 | compileStep.error({
49 | message: "Syntax error in " + compileStep.inputPath,
50 | line: e.line,
51 | column: e.column
52 | });
53 | }
54 | }
55 | // End code from mquandalle:bower
56 |
57 | function isHtmlExt(n){ return n.substr(-5).toLowerCase() === '.html' }
58 | // Used with Array.prototype.sort() in array of filenames to put '.html' first
59 | function sortHTMLFirst(a, b){
60 | var aHtml = isHtmlExt(a);
61 | var bHtml = isHtmlExt(b);
62 | if(aHtml && bHtml) return 0;
63 | else if(aHtml) return -1;
64 | else if(bHtml) return 1;
65 | return 0;
66 | }
67 |
68 | function generateBundleHandler(relativeRootPath) {
69 | return function(compileStep, bundles){
70 |
71 | var bundles =
72 | loadJSONContent(compileStep, compileStep.read().toString('utf8'));
73 |
74 | // Default settings
75 | var minify = false;
76 |
77 | // Settings provided in bundle description file
78 | if('#settings' in bundles) {
79 | minify = minify || bundles['#settings'].minify;
80 |
81 | delete bundles['#settings'];
82 | }
83 |
84 | for(var name in bundles) {
85 | var prefixLength = path.join(process.cwd(), relativeRootPath).length + 1;
86 | // Load list of all files included in this bundle, expanding globs
87 | var bundleSources = _.flatten(bundles[name].map(function(pattern) {
88 | return glob.sync(path.join(process.cwd(), relativeRootPath, pattern));
89 | })).map(function(file) {
90 | return file.substr(prefixLength);
91 | }).sort(sortHTMLFirst);
92 |
93 | var packageSource = new PackageSource;
94 | packageSource.initFromOptions('resources', {
95 | kind: 'plugin',
96 | sourceRoot: path.join(process.cwd(), relativeRootPath),
97 | serveRoot: process.cwd(),
98 | use: loadedPackages,
99 | npmDependencies: [],
100 | npmDir: path.join(process.cwd(), 'node_modules'),
101 | sources: bundleSources
102 | });
103 | // initFromOptions() defaults to 'os' architecture
104 | packageSource.architectures[0].arch = 'web.browser';
105 |
106 | var compiled = compiler.compile(packageSource, {
107 | packageMap: projectContext.packageMap,
108 | isopackCache: projectContext.isopackCache,
109 | includeCordovaUnibuild: false
110 | }).unibuilds[0];
111 |
112 | var scripts = compiled.prelinkFiles;
113 | var styleSheets = compiled.resources.filter(function(resource) {
114 | return resource.type === 'css';
115 | });
116 |
117 | if(minify) {
118 | var minifiers = isopackets.load('minifiers').minifiers;
119 | scripts.forEach(function(jsFile) {
120 | var result = minifiers.UglifyJS.minify(jsFile.source, {
121 | fromString: true
122 | });
123 |
124 | // Replace original source with minified source
125 | jsFile.source = result.code;
126 | delete jsFile.sourceMap;
127 | });
128 |
129 | styleSheets.forEach(function(styleSheet) {
130 | var result =
131 | minifiers.CssTools.minifyCss(styleSheet.data.toString());
132 |
133 | // Replace original source with minified source
134 | styleSheet.data = new Buffer(result);
135 | delete styleSheet.sourceMap;
136 | });
137 | }
138 |
139 | // Handle scripts
140 | scripts.forEach(function(script) {
141 | compileStep.addAsset({
142 | path: name + '.js',
143 | data: script.source
144 | });
145 | if(script.sourceMap) {
146 | compileStep.addAsset({
147 | path: name + '.js.map',
148 | data: script.sourceMap.replace(script.servePath, name + '.js')
149 | });
150 | }
151 | });
152 |
153 | // Handle stylesheets
154 | styleSheets.forEach(function(stylesheet) {
155 | compileStep.addAsset({
156 | path: name + '.css',
157 | data: stylesheet.data
158 | });
159 | if(stylesheet.sourceMap) {
160 | compileStep.addAsset({
161 | path: name + '.css.map',
162 | data: stylesheet.sourceMap.replace(
163 | stylesheet.servePath, name + '.css')
164 | });
165 | }
166 | });
167 | }
168 | }
169 | }
170 |
171 | Plugin.registerSourceHandler(
172 | 'publicbundles.json',
173 | { archMatching: 'web' },
174 | generateBundleHandler('public')
175 | );
176 |
177 | Plugin.registerSourceHandler(
178 | 'privatebundles.json',
179 | { archMatching: 'os' },
180 | generateBundleHandler('private')
181 | );
182 |
183 |
--------------------------------------------------------------------------------