├── .bowerrc ├── .editorconfig ├── .ember-cli ├── .gitignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── .watchmanconfig ├── LICENSE.md ├── README.md ├── TODO.md ├── addon ├── .gitkeep ├── lazy-router.js ├── resolver.js ├── routes │ └── -lazy-loader.js ├── services │ └── lazy-loader.js └── utils │ ├── -resource-helper.js │ ├── get-owner.js │ └── load-assets.js ├── app ├── .gitkeep ├── routes │ └── -lazy-loader.js └── services │ └── lazy-loader.js ├── approvals ├── a_dev_build.contains_an_index_file.approved.txt ├── a_dev_build.contains_dummy_css.approved.txt ├── a_dev_build.contains_dummy_js.approved.txt ├── a_dev_build.contains_package1_css.approved.txt ├── a_dev_build.contains_package1_js.approved.txt ├── a_dev_build.contains_package2_css.approved.txt ├── a_dev_build.contains_package2_js.approved.txt ├── a_dev_build.contains_vendor_css.approved.txt ├── a_dev_build.contains_vendor_js.approved.txt ├── config.js └── test.js ├── blueprints ├── .jshintrc ├── ember-cli-bundle-loader │ ├── files │ │ ├── app │ │ │ ├── resolver.js │ │ │ └── router.js │ │ ├── config │ │ │ ├── bundles.js │ │ │ └── package-names.js │ │ ├── ember-cli-build.js │ │ └── packages │ │ │ └── .gitkeep │ └── index.js └── package │ ├── files │ └── packages │ │ └── __name__ │ │ ├── components │ │ └── .gitkeep │ │ ├── controllers │ │ └── .gitkeep │ │ ├── helpers │ │ └── .gitkeep │ │ ├── models │ │ └── .gitkeep │ │ ├── resolvers │ │ └── .gitkeep │ │ ├── routes │ │ └── .gitkeep │ │ ├── styles │ │ └── app.scss │ │ └── templates │ │ └── .gitkeep │ └── index.js ├── bower.json ├── config ├── deploy.js ├── ember-try.js ├── environment.js └── release.js ├── ember-cli-build.js ├── index.js ├── lib ├── broccoli │ └── ember-app-with-packages.js └── utils │ └── get-bundle-configuration.js ├── package.json ├── testem.js ├── tests-node └── test.js ├── tests ├── .jshintrc ├── acceptance │ ├── a-resolver-test.js │ ├── get-owner-test.js │ ├── loading-substate-test.js │ ├── loads-dependent-package-test.js │ ├── query-params-test.js │ └── services │ │ └── lazy-loader-test.js ├── dummy │ ├── app │ │ ├── app.js │ │ ├── components │ │ │ ├── .gitkeep │ │ │ ├── loading-for-test.js │ │ │ └── my-component.js │ │ ├── controllers │ │ │ └── .gitkeep │ │ ├── helpers │ │ │ └── .gitkeep │ │ ├── index.html │ │ ├── models │ │ │ └── .gitkeep │ │ ├── resolver.js │ │ ├── router.js │ │ ├── routes │ │ │ ├── .gitkeep │ │ │ ├── application.js │ │ │ ├── boot.js │ │ │ └── package1 │ │ │ │ └── nested.js │ │ ├── styles │ │ │ └── app.scss │ │ └── templates │ │ │ ├── application.hbs │ │ │ ├── boot.hbs │ │ │ ├── components │ │ │ ├── .gitkeep │ │ │ ├── loading-for-test.hbs │ │ │ └── my-component.hbs │ │ │ ├── loading.hbs │ │ │ ├── package1.hbs │ │ │ └── package1 │ │ │ └── nested.hbs │ ├── config │ │ ├── bundles.js │ │ ├── environment.js │ │ └── package-names.js │ ├── packages │ │ ├── dependent │ │ │ ├── routes │ │ │ │ └── dependent.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ └── .gitkeep │ │ ├── link-source │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ └── link-source.hbs │ │ ├── link-target │ │ │ ├── controllers │ │ │ │ └── link-target.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ ├── .gitkeep │ │ │ │ └── link-target.hbs │ │ ├── load-assets-test │ │ │ ├── routes │ │ │ │ └── load-assets-test.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ └── .gitkeep │ │ ├── package1 │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── controllers │ │ │ │ └── .gitkeep │ │ │ ├── helpers │ │ │ │ └── .gitkeep │ │ │ ├── models │ │ │ │ └── .gitkeep │ │ │ ├── resolvers │ │ │ │ └── .gitkeep │ │ │ ├── routes │ │ │ │ ├── .gitkeep │ │ │ │ └── package1.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ ├── .gitkeep │ │ │ │ ├── package1.hbs │ │ │ │ └── package1 │ │ │ │ └── nested.hbs │ │ ├── package2 │ │ │ ├── components │ │ │ │ └── .gitkeep │ │ │ ├── controllers │ │ │ │ └── .gitkeep │ │ │ ├── helpers │ │ │ │ └── .gitkeep │ │ │ ├── models │ │ │ │ └── .gitkeep │ │ │ ├── resolvers │ │ │ │ └── .gitkeep │ │ │ ├── routes │ │ │ │ ├── .gitkeep │ │ │ │ └── package2.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ ├── .gitkeep │ │ │ │ └── package2.hbs │ │ ├── slow │ │ │ ├── routes │ │ │ │ └── slow.js │ │ │ ├── styles │ │ │ │ └── app.scss │ │ │ └── templates │ │ │ │ └── slow.hbs │ │ └── with-dependency │ │ │ ├── routes │ │ │ └── with-dependency.js │ │ │ ├── styles │ │ │ └── app.scss │ │ │ └── templates │ │ │ └── .gitkeep │ └── public │ │ ├── assets │ │ ├── load-assets-test2.css │ │ └── load-assets-test2.js │ │ ├── crossdomain.xml │ │ └── robots.txt ├── helpers │ ├── destroy-app.js │ ├── module-for-acceptance.js │ ├── resolver.js │ ├── skip-if-phantom.js │ └── start-app.js ├── index.html ├── integration │ ├── .gitkeep │ └── components │ │ └── my-component-test.js ├── test-helper.js └── unit │ ├── .gitkeep │ └── utils │ ├── load-assets-test.js │ └── resource-helper-test.js ├── vendor └── .gitkeep └── yarn.lock /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components", 3 | "analytics": false 4 | } 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.js] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | [*.hbs] 21 | insert_final_newline = false 22 | indent_style = space 23 | indent_size = 2 24 | 25 | [*.css] 26 | indent_style = space 27 | indent_size = 2 28 | 29 | [*.html] 30 | indent_style = space 31 | indent_size = 2 32 | 33 | [*.{diff,md}] 34 | trim_trailing_whitespace = false 35 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log 17 | testem.log 18 | approvals/**/*.received.* 19 | yarn-error.log 20 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "-Promise" 6 | ], 7 | "browser": true, 8 | "boss": true, 9 | "curly": true, 10 | "debug": false, 11 | "devel": true, 12 | "eqeqeq": true, 13 | "evil": true, 14 | "forin": false, 15 | "immed": false, 16 | "laxbreak": false, 17 | "newcap": true, 18 | "noarg": true, 19 | "noempty": false, 20 | "nonew": false, 21 | "nomen": false, 22 | "onevar": false, 23 | "plusplus": false, 24 | "regexp": false, 25 | "undef": true, 26 | "sub": true, 27 | "strict": false, 28 | "white": false, 29 | "eqnull": true, 30 | "esnext": true, 31 | "unused": true 32 | } 33 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /config/ember-try.js 3 | /dist 4 | /tests 5 | /tmp 6 | **/.gitkeep 7 | .bowerrc 8 | .editorconfig 9 | .ember-cli 10 | .gitignore 11 | .jshintrc 12 | .watchmanconfig 13 | .travis.yml 14 | bower.json 15 | ember-cli-build.js 16 | testem.js 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: node_js 3 | node_js: 4 | - "4.4.0" 5 | 6 | sudo: false 7 | 8 | cache: 9 | yarn: true 10 | directories: 11 | - node_modules 12 | 13 | env: 14 | - EMBER_TRY_SCENARIO=ember-1-13 15 | - EMBER_TRY_SCENARIO=ember-lts-2.4 16 | - EMBER_TRY_SCENARIO=ember-lts-2.8 17 | - EMBER_TRY_SCENARIO=ember-release 18 | - EMBER_TRY_SCENARIO=ember-beta 19 | - EMBER_TRY_SCENARIO=ember-canary 20 | 21 | matrix: 22 | fast_finish: true 23 | allow_failures: 24 | - env: EMBER_TRY_SCENARIO=ember-canary 25 | 26 | before_install: 27 | - export PATH=/usr/local/phantomjs-2.0.0/bin:$PATH 28 | - "npm config set spin false" 29 | - npm install yarn --global 30 | - yarn --version 31 | - npm install -g bower 32 | - "npm install -g npm@^2" 33 | - "npm install -g phantomjs-prebuilt" 34 | 35 | install: 36 | - yarn 37 | - bower install 38 | 39 | script: 40 | - npm test 41 | - ember try $EMBER_TRY_SCENARIO test 42 | 43 | branches: 44 | only: 45 | - master 46 | - beta 47 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Ember-cli-bundle-loader [![Build Status](https://travis-ci.org/MiguelMadero/ember-cli-bundle-loader.svg?branch=master)](https://travis-ci.org/MiguelMadero/ember-cli-bundle-loader) [![Download count all time](https://img.shields.io/npm/dt/ember-cli-bundle-loader.svg)](https://www.npmjs.com/package/ember-cli-bundle-loader) [![Ember Observer Score](http://emberobserver.com/badges/ember-cli-bundle-loader.svg)](http://emberobserver.com/addons/ember-cli-bundle-loader) 4 | 5 | [![Code Climate](https://codeclimate.com/github/MiguelMadero/ember-cli-bundle-loader/badges/gpa.svg)](https://codeclimate.com/github/MiguelMadero/ember-cli-bundle-loader) 6 | [![Test Coverage](https://codeclimate.com/github/MiguelMadero/ember-cli-bundle-loader/badges/coverage.svg)](https://codeclimate.com/github/MiguelMadero/ember-cli-bundle-loader/coverage) 7 | [![Dependency Status](https://www.versioneye.com/user/projects/57df010fbf3e4c0034e22b35/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/57df010fbf3e4c0034e22b35) 8 | [![Dependency Status](https://www.versioneye.com/user/projects/57df010b037c2000475cd3e9/badge.svg?style=flat-square)](https://www.versioneye.com/user/projects/57df010b037c2000475cd3e9) 9 | [![npm version](https://badge.fury.io/js/ember-cli-bundle-loader.svg)](https://badge.fury.io/js/ember-cli-bundle-loader) 10 | 11 | This project lets you build your app in different packages and load those packages lazily. The main goal of this is faster boot times for large applications, but it can also help with independentl build and deployments for different sub-products or sections of your app. 12 | 13 | You can see a demo live on http://miguelmadero.com/ember-cli-bundle-loader/ 14 | 15 | ## How it works 16 | 17 | We treat each package as an EmberApp, each of them will have its own JS and CSS output. For each package, it also changes certain things to avoid unnecessary processing of addons to get faster builds for packages. 18 | 19 | ## Installation 20 | 21 | ``` 22 | ember install MiguelMadero/ember-cli-bundle-loader # follow the prompts and diff 23 | ember generate package package-name 24 | ``` 25 | 26 | On a new app, simply override all the files when prompted during the `ember install` step. For existing apps, you can do a diff of each file. Most of the changes are simple and you can see an [example diff](https://github.com/MiguelMadero/ember-cli-bundle-loader-consumer/commit/d5791080ef915d84b7095e261701134267a73fd8). 27 | 28 | Now you can add routes to the main app (`app/router.js`) and to each package `(package-name/router.js`). Additionally, you will need to edit `config/bundles.js` with information about your package and the routes it handles. 29 | 30 | ## File Structure 31 | 32 | ### Current Ember Apps 33 | 34 | The typical output of an Ember App looks something like: 35 | 36 | - dist/ 37 | - index.html 38 | - assets/ 39 | app.js 40 | app.css 41 | vendor.js 42 | vendor.css 43 | 44 | ### Output of Packages with this addon 45 | 46 | - dist/ 47 | - index.html 48 | - assets/ 49 | boot.js 50 | boot.css 51 | package1.js 52 | package1.css 53 | package2.js 54 | package2.css 55 | vedor.js* 56 | vendor.csss 57 | 58 | \* We could also break vendor into smaller assets and define them as a dependency. More on this later. 59 | 60 | ### Source File Structure 61 | 62 | - app/ 63 | - index.html, *router.js*, resolver.js, app.js 64 | - routes/, controllers/, helpers/, models/, styles/, templates/, etc/ 65 | - pods/ 66 | - config 67 | - environment.js 68 | - bundles.js (new) 69 | - package-names.js (new) 70 | - packages (new) 71 | - package-name/ 72 | - index.html, *router.js*, resolver.js, app.js 73 | - routes/, controllers/, helpers/, models/, styles/, templates/, etc/ 74 | - pods/ 75 | - another-package/ 76 | - index.html, router.js, resolver.js, app.js 77 | - routes/, controllers/, helpers/, models/, styles/, templates/, etc/ 78 | - pods/ 79 | 80 | The app folder is identical to a normal EmberApp, it is, in fact just a normal EmberApp. This app is responsible for the booting everything. Only put here anything that is strictly required to get to the first page(s) or whatever is more important for a first time load. For example, your login page, the navbar, the default landing page. Each app will have different requirements, but the guidance is to keep it small. Initializers also have to be here since packages won't be available when we create the app. We could, in theory, lazy load initializers, but that doesn't make a lot of sense, so I have not tested it. 81 | 82 | There is a new top-level folder called `packages`, each package is like a normal EmberApp, with the exception that we don't need an index.html and we can't initializers. In the future this packages will become engines. 83 | 84 | Tests. Currently, all tests live under the traditional folders. It is suggested to create sub-folders like `tests/unit/package-name/` to provide some separation. In the future, tests for a package will move under each package folder. (Future: `packages/my-package/tests` and `packages/my-package/app`). In-repo-addons and engine have the same problem today see [issues#4461](https://github.com/ember-cli/ember-cli/issues/4461). 85 | 86 | ### JS 87 | 88 | All the JS modules are namespaced with the package name. For example, the route defined in `package1/routes/package1.js` is defined as `define('package1/routes/package1'` in the output code. This is because that's simply the name of the app when building. That gives us the advantage of being explicit about the way we consume and refer in code. However, this also requires a new resolver that can lookup for routes under the packages see `app/resolvers/packages.js` for more info. Please be aware of this namespace, it's especially important for `utils` or any other code that you import, for a hypothetical date-formatter utility under `package1/utils/date-formatter` will be imported as `import dateFormatter from 'package1/utils/date-formatter'`. Please be aware of this for tests. 89 | 90 | #### Vendor assets 91 | 92 | [ ] TODO: test 93 | We can define vendor assets as dependencies. Today, ember-cli supports specifying an `outputFile` when calling `app.import`. This works with static libraries and we'll add support to do it for addons. Once you have different vendor assets, you can simply define them as dependencies in `config/bundles.js`. For example: 94 | 95 | ``` 96 | // ember-cli-build.js 97 | var EmberAppWithPackages = require('./lib/broccoli/ember-app-with-packages'); 98 | module.exports = function (defaults) { 99 | var app = new EmberAppWithPackages(defaults); 100 | app.import('bower_components/moment/moment.js', {outputFile: 'vendor2.js'}); 101 | app.import('bower_components/lodash/lodash.js', {outputFile: 'vendor3.js'}); 102 | return app.toTree(); 103 | }; 104 | 105 | // /config/bundles.js 106 | module.exports = [{ 107 | name: 'package1', 108 | routeNames: ['^package1'] 109 | }, { 110 | name: 'package2', 111 | routeNames: ['^package2'] 112 | dependsOn: ['package1'] 113 | }]; 114 | ``` 115 | 116 | Based on the example above, when we go to `/package2`, we will load `vendor2.js`, `package1.js` and `vendor3.js`, only if they have not been loaded before. While the lbiraries are loaded in parallel, they will be executed in the order they were definied. 117 | 118 | #### Vendor assets from components 119 | 120 | Sometimes we can't depend on routes to load the packages, but instead, 121 | components are the ones that depend on a vendor lib. In this case 122 | they're responsible of initiating the load and providing a "loading" state. 123 | The following is an example using handsontable as a reference, assumine 124 | we have a handsontable wrapper: 125 | 126 | ``` 127 | // components/handson-table.js 128 | export default Ember.Component.extend({ 129 | lazyLoader: Ember.inject.service(), 130 | init () { 131 | this._super.apply(this, arguments); 132 | this.get('lazyLoader').loadBundle('handsontable').then(() => 133 | this.initHandsOnTableInstance()); 134 | }, 135 | didInsertElement () { 136 | this.get('isInDom', true); 137 | this.initHandsOnTableInstance(); 138 | }, 139 | initHandsOnTableInstance () { 140 | if (this.get('lazyLoader').isBundleLoaded('handsontable') && this.get('isInDom')) { 141 | // actual initialization of the wrapper 142 | // Often components need to wait for didInsert, in this case we need both, didInsert/ 143 | // and loading the assets. 144 | } 145 | } 146 | }) 147 | ``` 148 | 149 | On the HBS for the wrapper: 150 | 151 | ``` 152 | {{#if lazyLoader.loadedBundles.handsontable}} 153 | {{!-- markup for handsontable --}} 154 | {{else}} 155 |
Loading
156 | {{/if}} 157 | ``` 158 | 159 | In config/bundles.js 160 | 161 | ``` 162 | module.exports = [ 163 | { 164 | // Other bundles here... 165 | // Vendor bundles 166 | }, { 167 | name: 'handsontable', 168 | urls: ['/assets/handsontable.js', '/assets/handsontable.css'] 169 | } 170 | ]; 171 | 172 | ``` 173 | 174 | In ember-cli-build.js 175 | 176 | ``` 177 | app.import('/bower_components/handsontable/handsontable.full.min.js', {outputFile: 'handsontable.js') 178 | app.import('/bower_components/handsontable/handsontable.full.min.css', {outputFile: 'handsontable.css') 179 | ``` 180 | 181 | #### Potential issues 182 | 183 | The config/environment lives under `[modulePrefix]/config/environment`, which means it has the same path for every package. This is fine in most cases except if you're planning to share your packages across applications. 184 | 185 | ### CSS 186 | 187 | This demo uses ember-cli-sass, but the same technique would work with vanilla CSS (but please use a pre-processor) or Less. Is not tested with postCSS, but it isn't tested. 188 | 189 | ## Deploy 190 | 191 | To deploy the dummy app, with examples for lazy-loading, you can use `ember deploy development`, this will publish it to http://miguelmadero.com/ember-cli-bundle-loader/ 192 | 193 | 194 | ## Disclaimer 195 | 196 | *Note:* there is a ton of overlap with the work being done for * [ember engines](https://github.com/dgeb/ember-engines). While you might find this interesting, I strongly recommend you NOT to use these techniques and instead wait for ember-engines unless you're really desperate (like I am) to get lazy loading. 197 | 198 | ## Running Tests 199 | 200 | * `npm test` (Runs `ember try:testall` to test your addon against multiple Ember versions) 201 | * `ember test` 202 | * `ember test --server` 203 | 204 | ## References 205 | 206 | * [Ember-engines](https://github.com/dgeb/ember-engines). The "official" path going forward 207 | * [Ember-cli-lazy-load](https://github.com/duizendnegen/ember-cli-lazy-load). Another approach to lazy loading. Bundle-loader and lazy-load might merge in the future and both eventually deprecated in favor of engines. 208 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## General 2 | 3 | - [x] Make catch-all routes re-usable 4 | - [x] Extract cli-build API 5 | - [x] Test the addon and generators on a new app 6 | - [x] Update README with info from packages-demo and add stuff about generators 7 | Document sass dependency. 8 | - [x] Fix support for URLs 9 | - [x] Consider turning bundles.js into a service or util that the app could override 10 | as needed instead of keeping it in config/bundles so we can put CPs and code to resolve urls, etc. 11 | Note: it was a bad idea since we will use it later to do JS Concat to actually create the bundle. 12 | Instead the extension points will live in the existing loader service 13 | - [x] Port approvals tests from ember-cli-packages-demo 14 | - [x] Port acceptance tests. 15 | 16 | - [x] Fix link-to helper (add a new one or ditch catch-all in favor of route mixin) 17 | - [ ] Update route/-lazy-loader to only use routeName and avoid using url so we don't have to support to patterns and handledRoutes 18 | - [ ] Add acceptance test for deep-link, manual transition, anchor tag, normal link-to, link-to with model and nested routes 19 | - [x] Implement `needsLazyLoading` 20 | - [ ] Gracefully handle cases when a bundle can't be resolved 21 | - [ ] Better error handling for promises for catch-all route (or move away from catch-all) 22 | - [x] Fix tests for other ember versions (see 93e85db4ba) 23 | - [x] Change handledRoutesPatterns to use routeName instead of urls 24 | - [ ] Check if we still need locationType of hash 25 | 26 | - [x] Test pods 27 | ?- [x] Add support to override the namespace for packages. 28 | - [x] Setup CI 29 | - [ ] Check if we need to update the resolver for tests and update the generators if we do 30 | - [x] Make sure the loadScript promise works fine for crossOrigin (e.g. CDN). 31 | For same origin jquery simply does an eval and then calls `done`. Which works fine. 32 | For different origin it will add a script tag and it might call done before the script is executed, meaning that the router won't be available, see: [SO question](http://stackoverflow.com/questions/1130921/is-the-callback-on-jquerys-getscript-unreliable-or-am-i-doing-something-wrong). All the answers are horrible. 33 | Possible solution: search for Dynamically importing scripts in [this article](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement). 34 | We should basically do the same we're doing for links elements. 35 | 36 | 37 | ## From yp 38 | [ ] Fix the "isAddon" check in loader-bundler and add back 39 | [x] Add flexibily to specify a perPackageConfig 40 | [x] Add flexibility to specify a different path for the boot app 41 | [x] Add flexibility to specify a different path for each package 42 | 43 | ## Minor 44 | - [ ] Remove deprecation warnings (use getOwner API) 45 | - [ ] Fix watch for bundle.js and package-names.js 46 | - [ ] Avoid loading the bundle a second time. Right now I set the loadedBundles to true *after* the assets for that bundle are loader, that doesn't consider that someone can initiate a second request while the first one is in flight. I should return store the promise on the first request and return that on every subsequent call to `loadBundle` 47 | - [ ] Should we make this work with SRI? 48 | - [ ] Use path.join instead of concatenating paths in ember-app-with-packages.js [Windows?] 49 | - [ ] Fix OOB generators for packages (e.g. ember g component my-component --package=package1), test using -ir. 50 | - [x] Decide how to run packages tests. See in-repo addons 51 | This depends on the RFC for in-repo addon tests. 52 | - [ ] Make it work with other history locationType (right now it only works with hash) 53 | 54 | ## Later 55 | 56 | - [ ] Add support for bundles 57 | - [ ] Nested routes 58 | - [ ] More than one route per bundle 59 | - [ ] More than one package per bundle (concat) 60 | - [ ] Add support for bundle dependencies 61 | - [ ] Make sure a bundle is marked as "loaded" (or the promise re-used) if it was loaded as a dependency for another bundle. 62 | - [ ] Add support for vendor bundle dependencies 63 | 64 | 65 | ## Perf 66 | 67 | - [ ] Make sure we don't add app-boot, environment/config and other header/footer files from packages since it's already in boot. 68 | Consider overriding all of `EmberApp.prototype.javascript` or at least `this.concatFiles(appJs` to remove the `app-config.js` footerFile 69 | - [ ] Test perf 70 | - [ ] See what other trees we can remove for packages 71 | 72 | ## Documentation 73 | - [ ] Add links and link-to across routes and update links RFC with the learnings 74 | - [ ] Create RFC for addons {outputFile} similar to what we do today for vendor and bower_components. 75 | see: https://github.com/ember-cli/rfcs/pull/28 and 76 | - [ ] Write RFC for tests for in-repo addongs/engines/packages (see https://github.com/ember-cli/ember-cli/issues/4461 and https://github.com/ember-cli/rfcs/issues/44) 77 | 78 | ## Old todos for reference (from ember-cli-package-demo) 79 | - [x] Add tests to make sure the files are split and small (node tests) 80 | - [x] Bring packages-resolver (and hard code JS) 81 | - [x] Move packages to packages/ 82 | - [x] Lazy load JS 83 | - [x] Split Router.map? 84 | - [x] Dynamically determine the package to load for a given route 85 | - [x] Test LOG_TRANSITIONS_INTERNAL 86 | - [x] Test Engines to ensure allignment 87 | - [x] Lazy load CSS 88 | 89 | 90 | ## Reuse 91 | 92 | - [x] Consider splitting for better re-use 93 | Move to an addon: 94 | - [x] package-name generator and add them to config/environment changes to get packageNames 95 | - [x] bundle 96 | create a Package object that inherits from EmberApp and takes a config override to clean ember-cli-build 97 | Create an EmberAppWithPackages app that does packages and app and takes overrides for both. 98 | Expose from addon 99 | - [x] resolver 100 | - [x] service:lazy-loader, 101 | - [x] util:lazy-routing-configuration 102 | - [x] catch-all route 103 | -------------------------------------------------------------------------------- /addon/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/addon/.gitkeep -------------------------------------------------------------------------------- /addon/lazy-router.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | const { get, isArray } = Ember; 3 | import { getContainer, getFactory, registerFactory } from 'ember-cli-bundle-loader/utils/get-owner'; 4 | 5 | export default Ember.Router.extend({ 6 | _getHandlerFunction: function() { 7 | var container = getContainer(this); 8 | var DefaultRoute = getFactory(this, 'route:basic'); 9 | var LazyLoaderRoute =getFactory(this, 'route:-lazy-loader'); 10 | var lazyLoaderService = container.lookup('service:lazy-loader'); 11 | 12 | var _this = this; 13 | 14 | return function(name) { 15 | var routeName = 'route:' + name; 16 | var lazyRouteName = routeName + '.lazy'; 17 | var handler = container.lookup(routeName); 18 | var needsLazyLoading = !!lazyLoaderService.needsLazyLoading(name); 19 | 20 | if (!handler) { 21 | if (needsLazyLoading) { 22 | handler = container.lookup(lazyRouteName); 23 | if (!handler) { 24 | registerFactory(_this, lazyRouteName, LazyLoaderRoute.extend()); 25 | handler = container.lookup(lazyRouteName); 26 | handler.routeName = name + '-lazy'; 27 | } 28 | return handler; 29 | } 30 | registerFactory(_this, routeName, DefaultRoute.extend()); 31 | handler = container.lookup(routeName); 32 | 33 | if (get(_this, 'namespace.LOG_ACTIVE_GENERATION')) { 34 | Ember.Logger.info("generated -> " + routeName, { fullName: routeName }); 35 | } 36 | } 37 | 38 | if (typeof handler._setRouteName === 'function') { 39 | handler._setRouteName(name); 40 | handler._populateQPMeta(); 41 | } else { 42 | handler.routeName = name; 43 | } 44 | return handler; 45 | }; 46 | }, 47 | 48 | _queryParamsFor: function(handlerInfosOrLeafRouteName) { 49 | var leafRouteName = isArray(handlerInfosOrLeafRouteName) ? handlerInfosOrLeafRouteName[handlerInfosOrLeafRouteName.length - 1].name : handlerInfosOrLeafRouteName; 50 | var superQueryParams = this._super(...arguments); 51 | var container = getContainer(this); 52 | var lazyLoaderService = container.lookup('service:lazy-loader'); 53 | var needsLazyLoading = !!lazyLoaderService.needsLazyLoading(leafRouteName); 54 | //If the bundle is not yet loaded, the qps for the routes in the bundle will be stored as empty in `_qpCache`. 55 | //Hence remove the qps of routes that are not yet loaded from `qpCache` 56 | if (needsLazyLoading) { 57 | delete this._qpCache[leafRouteName]; 58 | } 59 | return superQueryParams; 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /addon/resolver.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import EmberResolver from 'ember-resolver'; 3 | import config from 'ember-get-config'; 4 | import packageNames from 'ember-cli-bundle-loader/config/package-names'; 5 | 6 | var lookupFunctions = [], 7 | genericModuleNameLookupPatterns = [ 8 | // NOTE: the order is important, since they're evaluted as we add them to the array 9 | // So we need the podBasedModuleName first and defaultModuleName last, just like the ember-resolver does 10 | 11 | function podBasedModuleName(packageName, parsedName) { 12 | // var podPrefix = this.namespace.podModulePrefix || this.namespace.modulePrefix; 13 | var podPrefix = packageName; 14 | if (config.podSubDirectory) { 15 | podPrefix = `${podPrefix}/${config.podSubDirectory}`; 16 | } 17 | return this.podBasedLookupWithPrefix(podPrefix, parsedName); 18 | }, 19 | 20 | function podBasedComponentsInSubdir(packageName, parsedName) { 21 | // var podPrefix = this.namespace.podModulePrefix || this.namespace.modulePrefix; 22 | var podPrefix = packageName; 23 | if (config.podSubDirectory) { 24 | podPrefix = `${podPrefix}/${config.podSubDirectory}`; 25 | } 26 | podPrefix = podPrefix + '/components'; 27 | 28 | if (parsedName.type === 'component' || parsedName.fullNameWithoutType.match(/^components/)) { 29 | return this.podBasedLookupWithPrefix(podPrefix, parsedName); 30 | } 31 | }, 32 | 33 | function mainModuleName(packageName, parsedName) { 34 | // if router:main or adapter:main look for a module with just the type first 35 | var tmpModuleName = /*parsedName.prefix + '/' +*/ packageName + '/' + parsedName.type; 36 | 37 | if (parsedName.fullNameWithoutType === 'main') { 38 | return tmpModuleName; 39 | } 40 | }, 41 | // Extensions the ember-resolver lookuppatterns that take a 'packageName' 42 | function defaultModuleName(packageName, parsedName) { 43 | return packageName + '/' + this.pluralize(parsedName.type) + '/' + parsedName.fullNameWithoutType; 44 | } 45 | ]; 46 | 47 | // The order is again important 48 | genericModuleNameLookupPatterns.forEach(function(genericLookupPattern) { 49 | packageNames.concat(config.modulePrefix).forEach(function(packageName) { 50 | lookupFunctions.push(function(parsedName) { 51 | return genericLookupPattern.call(this, packageName, parsedName); 52 | }); 53 | }); 54 | }); 55 | 56 | export default EmberResolver.extend({ 57 | moduleNameLookupPatterns: Ember.computed(function() { 58 | // Not sure if we need to delegate, this might be enough. 59 | // return lookupFunctions.concat(this._super()); 60 | return lookupFunctions; 61 | }) 62 | }); 63 | -------------------------------------------------------------------------------- /addon/routes/-lazy-loader.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | var retried = false; 4 | export default Ember.Route.extend({ 5 | lazyLoader: Ember.inject.service(), 6 | beforeModel: function (transition) { 7 | if (retried) { 8 | // Shortcircuit this in case the download fails. 9 | retried = !retried; 10 | return; 11 | } 12 | retried = !retried; 13 | var loadPromise = transition.intent.url ? 14 | this.get('lazyLoader').loadBundleForUrl(transition.intent.url) : 15 | this.get('lazyLoader').loadBundleForRouteName(transition.intent.name); 16 | return loadPromise.then(()=>{ 17 | transition.abort(); 18 | transition.retry(); 19 | retried = false; // reset this so we can transition to another lazy loaded section 20 | return {}; 21 | }); 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /addon/services/lazy-loader.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import bundles from 'ember-cli-bundle-loader/config/bundles'; 3 | import { getContainer } from 'ember-cli-bundle-loader/utils/get-owner'; 4 | import loadAssets from 'ember-cli-bundle-loader/utils/load-assets'; 5 | 6 | const {A, computed} = Ember; 7 | let loadedBundles = {}; 8 | 9 | export default Ember.Service.extend({ 10 | bundles: null, 11 | loadedBundles: computed(function () { 12 | return loadedBundles; 13 | }), 14 | 15 | init () { 16 | this._super(...arguments); 17 | this.setBundles(bundles); 18 | }, 19 | setBundles (bundles) { 20 | loadedBundles = {}; 21 | bundles.forEach(bundle=>loadedBundles[bundle.name] = false); 22 | this.set('bundles', bundles); 23 | }, 24 | needsLazyLoading (routeName) { 25 | var bundle = this.getBundleForRouteName(routeName); 26 | return bundle && !this.isBundleLoaded(bundle.name); 27 | }, 28 | isBundleLoaded (bundleName) { 29 | return loadedBundles[bundleName]; 30 | }, 31 | markBundleAsLoaded (bundleName) { 32 | loadedBundles[bundleName] = true; 33 | }, 34 | getBundleForRouteName (routeName) { 35 | return A(this.get('bundles')).find(bundle=> 36 | A(bundle.routeNames||[]).find(pattern=> 37 | routeName.match(pattern) && !A(bundle.blacklistedRouteNames||[]).find(blacklist=> 38 | routeName.match(blacklist)))); 39 | }, 40 | getBundleByName (bundleName) { 41 | return A(this.get('bundles')).find(bundle=> bundle.name === bundleName); 42 | }, 43 | loadBundleForUrl (url) { 44 | return this.loadBundleForRouteName(this._getRouteNameFromUrl(url)); 45 | }, 46 | loadBundleForRouteName (routeName) { 47 | return this.loadBundle(this.getBundleForRouteName(routeName)); 48 | }, 49 | loadBundle (bundleOrBundleName) { 50 | const bundle = typeof bundleOrBundleName === 'string' ? this.getBundleByName(bundleOrBundleName) : bundleOrBundleName; 51 | if (!bundle) { 52 | Ember.assert('A bundle was expected, but we couldn\'t find it', bundle); 53 | return Ember.RSVP.resolve(); 54 | } 55 | if (this.isBundleLoaded(bundle.name)) { 56 | return Ember.RSVP.resolve(); 57 | } 58 | 59 | return Ember.RSVP.all(this.getDependentBundlesForBundle(bundle).map(bundle => { 60 | return loadAssets(bundle.urls).then(()=>this.markBundleAsLoaded(bundle.name)); 61 | })); 62 | }, 63 | 64 | getDependentBundlesForBundle(rootBundle) { 65 | var self = this; 66 | 67 | var dependentBundles = []; 68 | // seenBundleNames is a map of bundle name -> bundle -- need O(1) collection management. 69 | var seenBundleNames = {}; 70 | seenBundleNames[rootBundle.name] = true; 71 | 72 | function _addDependents(dependentBundleNames) { 73 | dependentBundleNames.forEach(function(dependencyName) { 74 | if (seenBundleNames[dependencyName]) { 75 | return; 76 | } 77 | var dependencyBundle = self.getBundleByName(dependencyName); 78 | seenBundleNames[dependencyBundle.name] = true; 79 | // Adds its dependents before we add this module 80 | _addDependents(dependencyBundle.dependsOn || []); 81 | dependentBundles.push(dependencyBundle); 82 | }); 83 | } 84 | _addDependents(rootBundle.dependsOn || []); 85 | // Added at the end, since this is the last bundle we should load 86 | dependentBundles.push(rootBundle); 87 | 88 | return dependentBundles; 89 | }, 90 | 91 | _getRouteNameFromUrl (url) { 92 | const router = getContainer(this).lookup('router:main'); 93 | const routes = router.router.recognizer.recognize(url); 94 | if (routes && routes.length) { 95 | return routes[routes.length-1].handler; 96 | } 97 | } 98 | }); 99 | -------------------------------------------------------------------------------- /addon/utils/-resource-helper.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import config from 'ember-get-config'; 3 | const {get, $} = Ember; 4 | 5 | export default { 6 | loadJavascript(url) { 7 | let async = get(config, 'ember-cli-bundle-loader.asyncScriptExecution'); 8 | if (async === undefined) { 9 | // For backwards compatibility we use async true 10 | async = true; 11 | } 12 | 13 | var scriptElement = $(" 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_dummy_css.approved.txt: -------------------------------------------------------------------------------- 1 | .boot { 2 | background: red; } 3 | 4 | /*# sourceMappingURL=dummy.css.map */ 5 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_dummy_js.approved.txt: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* jshint ignore:start */ 4 | 5 | 6 | 7 | /* jshint ignore:end */ 8 | 9 | define('dummy/app', ['exports', 'ember', 'dummy/resolver', 'ember-load-initializers', 'dummy/config/environment'], function (exports, _ember, _dummyResolver, _emberLoadInitializers, _dummyConfigEnvironment) { 10 | 11 | var App = undefined; 12 | 13 | _ember['default'].MODEL_FACTORY_INJECTIONS = true; 14 | 15 | App = _ember['default'].Application.extend({ 16 | modulePrefix: _dummyConfigEnvironment['default'].modulePrefix, 17 | podModulePrefix: _dummyConfigEnvironment['default'].podModulePrefix, 18 | Resolver: _dummyResolver['default'] 19 | }); 20 | 21 | (0, _emberLoadInitializers['default'])(App, _dummyConfigEnvironment['default'].modulePrefix); 22 | 23 | exports['default'] = App; 24 | }); 25 | define('dummy/components/loading-for-test', ['exports', 'ember', 'dummy/templates/components/loading-for-test'], function (exports, _ember, _dummyTemplatesComponentsLoadingForTest) { 26 | var StateForTest = { hasRendered: false }; 27 | exports.StateForTest = StateForTest; 28 | exports['default'] = _ember['default'].Component.extend({ 29 | layout: _dummyTemplatesComponentsLoadingForTest['default'], 30 | didInsertElement: function didInsertElement() { 31 | // Not an easy way to prove that something render 32 | // since checking for a class on run.later 33 | // actually delays the render :( 34 | StateForTest.hasRendered = true; 35 | } 36 | }); 37 | }); 38 | define('dummy/components/my-component', ['exports', 'ember', 'dummy/templates/components/my-component'], function (exports, _ember, _dummyTemplatesComponentsMyComponent) { 39 | exports['default'] = _ember['default'].Component.extend({ 40 | layout: _dummyTemplatesComponentsMyComponent['default'] 41 | }); 42 | }); 43 | define('dummy/controllers/array', ['exports', 'ember'], function (exports, _ember) { 44 | exports['default'] = _ember['default'].Controller; 45 | }); 46 | define('dummy/controllers/object', ['exports', 'ember'], function (exports, _ember) { 47 | exports['default'] = _ember['default'].Controller; 48 | }); 49 | define('dummy/initializers/container-debug-adapter', ['exports', 'ember-resolver/container-debug-adapter'], function (exports, _emberResolverContainerDebugAdapter) { 50 | exports['default'] = { 51 | name: 'container-debug-adapter', 52 | 53 | initialize: function initialize() { 54 | var app = arguments[1] || arguments[0]; 55 | 56 | app.register('container-debug-adapter:main', _emberResolverContainerDebugAdapter['default']); 57 | app.inject('container-debug-adapter:main', 'namespace', 'application:main'); 58 | } 59 | }; 60 | }); 61 | define('dummy/initializers/export-application-global', ['exports', 'ember', 'dummy/config/environment'], function (exports, _ember, _dummyConfigEnvironment) { 62 | exports.initialize = initialize; 63 | 64 | function initialize() { 65 | var application = arguments[1] || arguments[0]; 66 | if (_dummyConfigEnvironment['default'].exportApplicationGlobal !== false) { 67 | var theGlobal; 68 | if (typeof window !== 'undefined') { 69 | theGlobal = window; 70 | } else if (typeof global !== 'undefined') { 71 | theGlobal = global; 72 | } else if (typeof self !== 'undefined') { 73 | theGlobal = self; 74 | } else { 75 | // no reasonable global, just bail 76 | return; 77 | } 78 | 79 | var value = _dummyConfigEnvironment['default'].exportApplicationGlobal; 80 | var globalName; 81 | 82 | if (typeof value === 'string') { 83 | globalName = value; 84 | } else { 85 | globalName = _ember['default'].String.classify(_dummyConfigEnvironment['default'].modulePrefix); 86 | } 87 | 88 | if (!theGlobal[globalName]) { 89 | theGlobal[globalName] = application; 90 | 91 | application.reopen({ 92 | willDestroy: function willDestroy() { 93 | this._super.apply(this, arguments); 94 | delete theGlobal[globalName]; 95 | } 96 | }); 97 | } 98 | } 99 | } 100 | 101 | exports['default'] = { 102 | name: 'export-application-global', 103 | 104 | initialize: initialize 105 | }; 106 | }); 107 | define('dummy/resolver', ['exports', 'ember-cli-bundle-loader/resolver'], function (exports, _emberCliBundleLoaderResolver) { 108 | exports['default'] = _emberCliBundleLoaderResolver['default']; 109 | }); 110 | define('dummy/router', ['exports', 'ember-cli-bundle-loader/lazy-router', 'dummy/config/environment'], function (exports, _emberCliBundleLoaderLazyRouter, _dummyConfigEnvironment) { 111 | 112 | var Router = _emberCliBundleLoaderLazyRouter['default'].extend({ 113 | location: _dummyConfigEnvironment['default'].locationType 114 | }); 115 | 116 | Router.map(function () { 117 | this.route('boot'); 118 | this.route('package1', function () { 119 | this.route('nested', { path: 'nested/:id' }); 120 | }); 121 | this.route('package2'); 122 | this.route('link-source'); 123 | this.route('link-target'); 124 | this.route('slow'); 125 | this.route('with-dependency'); 126 | }); 127 | 128 | exports['default'] = Router; 129 | }); 130 | define('dummy/routes/-lazy-loader', ['exports', 'ember-cli-bundle-loader/routes/-lazy-loader'], function (exports, _emberCliBundleLoaderRoutesLazyLoader) { 131 | Object.defineProperty(exports, 'default', { 132 | enumerable: true, 133 | get: function get() { 134 | return _emberCliBundleLoaderRoutesLazyLoader['default']; 135 | } 136 | }); 137 | }); 138 | define('dummy/routes/application', ['exports', 'ember'], function (exports, _ember) { 139 | exports['default'] = _ember['default'].Route.extend({ 140 | actions: { 141 | manualTransition: function manualTransition() { 142 | this.get('router')._doTransition('package1', [], []); 143 | } 144 | } 145 | }); 146 | }); 147 | define('dummy/routes/boot', ['exports', 'ember'], function (exports, _ember) { 148 | exports['default'] = _ember['default'].Route.extend({}); 149 | }); 150 | define('dummy/routes/package1/nested', ['exports', 'ember'], function (exports, _ember) { 151 | exports['default'] = _ember['default'].Route.extend({ 152 | debug: 'from-package1', 153 | model: function model() { 154 | return new _ember['default'].RSVP.Promise(function (resolve) { 155 | _ember['default'].run.later(function () { 156 | return resolve({ modelProperty: 42 }); 157 | }, 1000); 158 | }); 159 | } 160 | }); 161 | }); 162 | define('dummy/services/ajax', ['exports', 'ember-ajax/services/ajax'], function (exports, _emberAjaxServicesAjax) { 163 | Object.defineProperty(exports, 'default', { 164 | enumerable: true, 165 | get: function get() { 166 | return _emberAjaxServicesAjax['default']; 167 | } 168 | }); 169 | }); 170 | define('dummy/services/lazy-loader', ['exports', 'ember-cli-bundle-loader/services/lazy-loader'], function (exports, _emberCliBundleLoaderServicesLazyLoader) { 171 | Object.defineProperty(exports, 'default', { 172 | enumerable: true, 173 | get: function get() { 174 | return _emberCliBundleLoaderServicesLazyLoader['default']; 175 | } 176 | }); 177 | }); 178 | define("dummy/templates/application", ["exports"], function (exports) { 179 | exports["default"] = Ember.HTMLBars.template((function () { 180 | var child0 = (function () { 181 | return { 182 | meta: { 183 | "revision": "Ember@1.13.13", 184 | "loc": { 185 | "source": null, 186 | "start": { 187 | "line": 5, 188 | "column": 6 189 | }, 190 | "end": { 191 | "line": 5, 192 | "column": 38 193 | } 194 | }, 195 | "moduleName": "dummy/templates/application.hbs" 196 | }, 197 | arity: 0, 198 | cachedFragment: null, 199 | hasRendered: false, 200 | buildFragment: function buildFragment(dom) { 201 | var el0 = dom.createDocumentFragment(); 202 | var el1 = dom.createTextNode("Package 1"); 203 | dom.appendChild(el0, el1); 204 | return el0; 205 | }, 206 | buildRenderNodes: function buildRenderNodes() { 207 | return []; 208 | }, 209 | statements: [], 210 | locals: [], 211 | templates: [] 212 | }; 213 | })(); 214 | var child1 = (function () { 215 | return { 216 | meta: { 217 | "revision": "Ember@1.13.13", 218 | "loc": { 219 | "source": null, 220 | "start": { 221 | "line": 6, 222 | "column": 6 223 | }, 224 | "end": { 225 | "line": 6, 226 | "column": 46 227 | } 228 | }, 229 | "moduleName": "dummy/templates/application.hbs" 230 | }, 231 | arity: 0, 232 | cachedFragment: null, 233 | hasRendered: false, 234 | buildFragment: function buildFragment(dom) { 235 | var el0 = dom.createDocumentFragment(); 236 | var el1 = dom.createTextNode("Nested 1"); 237 | dom.appendChild(el0, el1); 238 | return el0; 239 | }, 240 | buildRenderNodes: function buildRenderNodes() { 241 | return []; 242 | }, 243 | statements: [], 244 | locals: [], 245 | templates: [] 246 | }; 247 | })(); 248 | var child2 = (function () { 249 | return { 250 | meta: { 251 | "revision": "Ember@1.13.13", 252 | "loc": { 253 | "source": null, 254 | "start": { 255 | "line": 10, 256 | "column": 6 257 | }, 258 | "end": { 259 | "line": 10, 260 | "column": 29 261 | } 262 | }, 263 | "moduleName": "dummy/templates/application.hbs" 264 | }, 265 | arity: 0, 266 | cachedFragment: null, 267 | hasRendered: false, 268 | buildFragment: function buildFragment(dom) { 269 | var el0 = dom.createDocumentFragment(); 270 | var el1 = dom.createTextNode("Slow"); 271 | dom.appendChild(el0, el1); 272 | return el0; 273 | }, 274 | buildRenderNodes: function buildRenderNodes() { 275 | return []; 276 | }, 277 | statements: [], 278 | locals: [], 279 | templates: [] 280 | }; 281 | })(); 282 | return { 283 | meta: { 284 | "revision": "Ember@1.13.13", 285 | "loc": { 286 | "source": null, 287 | "start": { 288 | "line": 1, 289 | "column": 0 290 | }, 291 | "end": { 292 | "line": 13, 293 | "column": 10 294 | } 295 | }, 296 | "moduleName": "dummy/templates/application.hbs" 297 | }, 298 | arity: 0, 299 | cachedFragment: null, 300 | hasRendered: false, 301 | buildFragment: function buildFragment(dom) { 302 | var el0 = dom.createDocumentFragment(); 303 | var el1 = dom.createElement("h1"); 304 | var el2 = dom.createTextNode("Welcome to Ember - with packaging and lazy loading"); 305 | dom.appendChild(el1, el2); 306 | dom.appendChild(el0, el1); 307 | var el1 = dom.createTextNode("\n"); 308 | dom.appendChild(el0, el1); 309 | var el1 = dom.createElement("ul"); 310 | var el2 = dom.createTextNode("\n "); 311 | dom.appendChild(el1, el2); 312 | var el2 = dom.createComment(" TODO: change it to test link-to "); 313 | dom.appendChild(el1, el2); 314 | var el2 = dom.createTextNode("\n "); 315 | dom.appendChild(el1, el2); 316 | var el2 = dom.createElement("li"); 317 | var el3 = dom.createElement("a"); 318 | dom.setAttribute(el3, "href", "#/boot"); 319 | var el4 = dom.createTextNode("Boot"); 320 | dom.appendChild(el3, el4); 321 | dom.appendChild(el2, el3); 322 | dom.appendChild(el1, el2); 323 | var el2 = dom.createTextNode("\n "); 324 | dom.appendChild(el1, el2); 325 | var el2 = dom.createElement("li"); 326 | var el3 = dom.createComment(""); 327 | dom.appendChild(el2, el3); 328 | dom.appendChild(el1, el2); 329 | var el2 = dom.createTextNode("\n "); 330 | dom.appendChild(el1, el2); 331 | var el2 = dom.createElement("li"); 332 | var el3 = dom.createComment(""); 333 | dom.appendChild(el2, el3); 334 | dom.appendChild(el1, el2); 335 | var el2 = dom.createTextNode("\n "); 336 | dom.appendChild(el1, el2); 337 | var el2 = dom.createElement("li"); 338 | var el3 = dom.createElement("a"); 339 | dom.setAttribute(el3, "href", "#/package1"); 340 | var el4 = dom.createTextNode("Package 1 (by url)"); 341 | dom.appendChild(el3, el4); 342 | dom.appendChild(el2, el3); 343 | dom.appendChild(el1, el2); 344 | var el2 = dom.createTextNode("\n "); 345 | dom.appendChild(el1, el2); 346 | var el2 = dom.createElement("li"); 347 | var el3 = dom.createElement("a"); 348 | dom.setAttribute(el3, "href", "#/package2"); 349 | var el4 = dom.createTextNode("Package 2 (by url)"); 350 | dom.appendChild(el3, el4); 351 | dom.appendChild(el2, el3); 352 | dom.appendChild(el1, el2); 353 | var el2 = dom.createTextNode("\n"); 354 | dom.appendChild(el1, el2); 355 | var el2 = dom.createTextNode(" "); 356 | dom.appendChild(el1, el2); 357 | var el2 = dom.createElement("li"); 358 | var el3 = dom.createComment(""); 359 | dom.appendChild(el2, el3); 360 | dom.appendChild(el1, el2); 361 | var el2 = dom.createTextNode("\n "); 362 | dom.appendChild(el1, el2); 363 | var el2 = dom.createElement("li"); 364 | var el3 = dom.createElement("a"); 365 | dom.setAttribute(el3, "href", "#"); 366 | var el4 = dom.createTextNode("Manual transition"); 367 | dom.appendChild(el3, el4); 368 | dom.appendChild(el2, el3); 369 | dom.appendChild(el1, el2); 370 | var el2 = dom.createTextNode("\n"); 371 | dom.appendChild(el1, el2); 372 | dom.appendChild(el0, el1); 373 | var el1 = dom.createTextNode("\n"); 374 | dom.appendChild(el0, el1); 375 | var el1 = dom.createComment(""); 376 | dom.appendChild(el0, el1); 377 | return el0; 378 | }, 379 | buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 380 | var element0 = dom.childAt(fragment, [2]); 381 | var element1 = dom.childAt(element0, [16, 0]); 382 | var morphs = new Array(5); 383 | morphs[0] = dom.createMorphAt(dom.childAt(element0, [5]), 0, 0); 384 | morphs[1] = dom.createMorphAt(dom.childAt(element0, [7]), 0, 0); 385 | morphs[2] = dom.createMorphAt(dom.childAt(element0, [14]), 0, 0); 386 | morphs[3] = dom.createElementMorph(element1); 387 | morphs[4] = dom.createMorphAt(fragment, 4, 4, contextualElement); 388 | dom.insertBoundary(fragment, null); 389 | return morphs; 390 | }, 391 | statements: [["block", "link-to", ["package1"], [], 0, null, ["loc", [null, [5, 6], [5, 50]]]], ["block", "link-to", ["package1.nested", 1], [], 1, null, ["loc", [null, [6, 6], [6, 58]]]], ["block", "link-to", ["slow"], [], 2, null, ["loc", [null, [10, 6], [10, 41]]]], ["element", "action", ["manualTransition"], [], ["loc", [null, [11, 18], [11, 47]]]], ["content", "outlet", ["loc", [null, [13, 0], [13, 10]]]]], 392 | locals: [], 393 | templates: [child0, child1, child2] 394 | }; 395 | })()); 396 | }); 397 | define("dummy/templates/boot", ["exports"], function (exports) { 398 | exports["default"] = Ember.HTMLBars.template((function () { 399 | return { 400 | meta: { 401 | "revision": "Ember@1.13.13", 402 | "loc": { 403 | "source": null, 404 | "start": { 405 | "line": 1, 406 | "column": 0 407 | }, 408 | "end": { 409 | "line": 3, 410 | "column": 6 411 | } 412 | }, 413 | "moduleName": "dummy/templates/boot.hbs" 414 | }, 415 | arity: 0, 416 | cachedFragment: null, 417 | hasRendered: false, 418 | buildFragment: function buildFragment(dom) { 419 | var el0 = dom.createDocumentFragment(); 420 | var el1 = dom.createElement("div"); 421 | dom.setAttribute(el1, "class", "boot"); 422 | var el2 = dom.createTextNode("\n Boot\n"); 423 | dom.appendChild(el1, el2); 424 | dom.appendChild(el0, el1); 425 | return el0; 426 | }, 427 | buildRenderNodes: function buildRenderNodes() { 428 | return []; 429 | }, 430 | statements: [], 431 | locals: [], 432 | templates: [] 433 | }; 434 | })()); 435 | }); 436 | define("dummy/templates/components/loading-for-test", ["exports"], function (exports) { 437 | exports["default"] = Ember.HTMLBars.template((function () { 438 | return { 439 | meta: { 440 | "revision": "Ember@1.13.13", 441 | "loc": { 442 | "source": null, 443 | "start": { 444 | "line": 1, 445 | "column": 0 446 | }, 447 | "end": { 448 | "line": 1, 449 | "column": 38 450 | } 451 | }, 452 | "moduleName": "dummy/templates/components/loading-for-test.hbs" 453 | }, 454 | arity: 0, 455 | cachedFragment: null, 456 | hasRendered: false, 457 | buildFragment: function buildFragment(dom) { 458 | var el0 = dom.createDocumentFragment(); 459 | var el1 = dom.createElement("div"); 460 | dom.setAttribute(el1, "class", "loading"); 461 | var el2 = dom.createTextNode("LOADING...."); 462 | dom.appendChild(el1, el2); 463 | dom.appendChild(el0, el1); 464 | return el0; 465 | }, 466 | buildRenderNodes: function buildRenderNodes() { 467 | return []; 468 | }, 469 | statements: [], 470 | locals: [], 471 | templates: [] 472 | }; 473 | })()); 474 | }); 475 | define("dummy/templates/components/my-component", ["exports"], function (exports) { 476 | exports["default"] = Ember.HTMLBars.template((function () { 477 | return { 478 | meta: { 479 | "revision": "Ember@1.13.13", 480 | "loc": { 481 | "source": null, 482 | "start": { 483 | "line": 1, 484 | "column": 0 485 | }, 486 | "end": { 487 | "line": 2, 488 | "column": 0 489 | } 490 | }, 491 | "moduleName": "dummy/templates/components/my-component.hbs" 492 | }, 493 | arity: 0, 494 | cachedFragment: null, 495 | hasRendered: false, 496 | buildFragment: function buildFragment(dom) { 497 | var el0 = dom.createDocumentFragment(); 498 | var el1 = dom.createComment(""); 499 | dom.appendChild(el0, el1); 500 | var el1 = dom.createTextNode("\n"); 501 | dom.appendChild(el0, el1); 502 | return el0; 503 | }, 504 | buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 505 | var morphs = new Array(1); 506 | morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 507 | dom.insertBoundary(fragment, 0); 508 | return morphs; 509 | }, 510 | statements: [["content", "yield", ["loc", [null, [1, 0], [1, 9]]]]], 511 | locals: [], 512 | templates: [] 513 | }; 514 | })()); 515 | }); 516 | define("dummy/templates/loading", ["exports"], function (exports) { 517 | exports["default"] = Ember.HTMLBars.template((function () { 518 | return { 519 | meta: { 520 | "revision": "Ember@1.13.13", 521 | "loc": { 522 | "source": null, 523 | "start": { 524 | "line": 1, 525 | "column": 0 526 | }, 527 | "end": { 528 | "line": 1, 529 | "column": 20 530 | } 531 | }, 532 | "moduleName": "dummy/templates/loading.hbs" 533 | }, 534 | arity: 0, 535 | cachedFragment: null, 536 | hasRendered: false, 537 | buildFragment: function buildFragment(dom) { 538 | var el0 = dom.createDocumentFragment(); 539 | var el1 = dom.createComment(""); 540 | dom.appendChild(el0, el1); 541 | return el0; 542 | }, 543 | buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 544 | var morphs = new Array(1); 545 | morphs[0] = dom.createMorphAt(fragment, 0, 0, contextualElement); 546 | dom.insertBoundary(fragment, 0); 547 | dom.insertBoundary(fragment, null); 548 | return morphs; 549 | }, 550 | statements: [["content", "loading-for-test", ["loc", [null, [1, 0], [1, 20]]]]], 551 | locals: [], 552 | templates: [] 553 | }; 554 | })()); 555 | }); 556 | define("dummy/templates/package1", ["exports"], function (exports) { 557 | exports["default"] = Ember.HTMLBars.template((function () { 558 | return { 559 | meta: { 560 | "revision": "Ember@1.13.13", 561 | "loc": { 562 | "source": null, 563 | "start": { 564 | "line": 1, 565 | "column": 0 566 | }, 567 | "end": { 568 | "line": 4, 569 | "column": 10 570 | } 571 | }, 572 | "moduleName": "dummy/templates/package1.hbs" 573 | }, 574 | arity: 0, 575 | cachedFragment: null, 576 | hasRendered: false, 577 | buildFragment: function buildFragment(dom) { 578 | var el0 = dom.createDocumentFragment(); 579 | var el1 = dom.createElement("div"); 580 | var el2 = dom.createTextNode("\n Test 1 - this should never be used since the package1 template will take precedence\n"); 581 | dom.appendChild(el1, el2); 582 | dom.appendChild(el0, el1); 583 | var el1 = dom.createTextNode("\n"); 584 | dom.appendChild(el0, el1); 585 | var el1 = dom.createComment(""); 586 | dom.appendChild(el0, el1); 587 | return el0; 588 | }, 589 | buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 590 | var morphs = new Array(1); 591 | morphs[0] = dom.createMorphAt(fragment, 2, 2, contextualElement); 592 | dom.insertBoundary(fragment, null); 593 | return morphs; 594 | }, 595 | statements: [["content", "outlet", ["loc", [null, [4, 0], [4, 10]]]]], 596 | locals: [], 597 | templates: [] 598 | }; 599 | })()); 600 | }); 601 | define("dummy/templates/package1/nested", ["exports"], function (exports) { 602 | exports["default"] = Ember.HTMLBars.template((function () { 603 | return { 604 | meta: { 605 | "revision": "Ember@1.13.13", 606 | "loc": { 607 | "source": null, 608 | "start": { 609 | "line": 1, 610 | "column": 0 611 | }, 612 | "end": { 613 | "line": 2, 614 | "column": 0 615 | } 616 | }, 617 | "moduleName": "dummy/templates/package1/nested.hbs" 618 | }, 619 | arity: 0, 620 | cachedFragment: null, 621 | hasRendered: false, 622 | buildFragment: function buildFragment(dom) { 623 | var el0 = dom.createDocumentFragment(); 624 | var el1 = dom.createTextNode("Nested - this should never be used since the package1 template will take precedence\n"); 625 | dom.appendChild(el0, el1); 626 | return el0; 627 | }, 628 | buildRenderNodes: function buildRenderNodes() { 629 | return []; 630 | }, 631 | statements: [], 632 | locals: [], 633 | templates: [] 634 | }; 635 | })()); 636 | }); 637 | /* jshint ignore:start */ 638 | 639 | 640 | 641 | /* jshint ignore:end */ 642 | 643 | /* jshint ignore:start */ 644 | 645 | define('dummy/config/environment', ['ember'], function(Ember) { 646 | var prefix = 'dummy'; 647 | /* jshint ignore:start */ 648 | 649 | try { 650 | var metaName = prefix + '/config/environment'; 651 | var rawConfig = Ember['default'].$('meta[name="' + metaName + '"]').attr('content'); 652 | var config = JSON.parse(unescape(rawConfig)); 653 | 654 | return { 'default': config }; 655 | } 656 | catch(err) { 657 | throw new Error('Could not read config from meta tag with name "' + metaName + '".'); 658 | } 659 | 660 | /* jshint ignore:end */ 661 | 662 | }); 663 | 664 | /* jshint ignore:end */ 665 | 666 | /* jshint ignore:start */ 667 | 668 | define('ember-cli-bundle-loader/config/bundles', function() { 669 | return [{"name":"package1","packages":["package1"],"urls":["assets/package1.js","assets/package1.css"],"routeNames":["^package1"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":["with-dependency"],"packages":[["with-dependency"]],"urls":["assets/with-dependency.js","assets/with-dependency.css"],"routeNames":["^with-dependency"],"dependsOn":["dependent"],"blacklistedRouteNames":[]},{"name":"package-with-wrong-urls","packages":["package-with-wrong-urls"],"urls":["dosntexist.js"],"routeNames":["^package-with-wrong-urls"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"dependent","packages":["dependent"],"urls":["assets/dependent.js","assets/dependent.css"],"routeNames":["^dependent"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"link-source","packages":["link-source"],"urls":["assets/link-source.js","assets/link-source.css"],"routeNames":["^link-source"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"link-target","packages":["link-target"],"urls":["assets/link-target.js","assets/link-target.css"],"routeNames":["^link-target"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"load-assets-test","packages":["load-assets-test"],"urls":["assets/load-assets-test.js","assets/load-assets-test.css"],"routeNames":["^load-assets-test"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"package2","packages":["package2"],"urls":["assets/package2.js","assets/package2.css"],"routeNames":["^package2"],"dependsOn":[],"blacklistedRouteNames":[]},{"name":"slow","packages":["slow"],"urls":["assets/slow.js","assets/slow.css"],"routeNames":["^slow"],"dependsOn":[],"blacklistedRouteNames":[]}] 670 | }); 671 | define('ember-cli-bundle-loader/config/package-names', function() { 672 | return ["dependent","link-source","link-target","load-assets-test","package1","package2","slow","with-dependency"] 673 | }); 674 | if (!runningTests) { 675 | require("dummy/app")["default"].create({}); 676 | } 677 | 678 | /* jshint ignore:end */ 679 | //# sourceMappingURL=dummy.map 680 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_package1_css.approved.txt: -------------------------------------------------------------------------------- 1 | .package1 { 2 | background: green; } 3 | 4 | /*# sourceMappingURL=package1.css.map */ 5 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_package1_js.approved.txt: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* jshint ignore:start */ 4 | 5 | 6 | 7 | /* jshint ignore:end */ 8 | 9 | define('package1/routes/package1', ['exports', 'ember'], function (exports, _ember) { 10 | exports['default'] = _ember['default'].Route.extend({ 11 | debug: 'from-package1', 12 | model: function model() { 13 | return { modelProperty: 42 }; 14 | } 15 | }); 16 | }); 17 | define("package1/templates/package1", ["exports"], function (exports) { 18 | exports["default"] = Ember.HTMLBars.template((function () { 19 | return { 20 | meta: { 21 | "revision": "Ember@1.13.13", 22 | "loc": { 23 | "source": null, 24 | "start": { 25 | "line": 1, 26 | "column": 0 27 | }, 28 | "end": { 29 | "line": 5, 30 | "column": 10 31 | } 32 | }, 33 | "moduleName": "package1/templates/package1.hbs" 34 | }, 35 | arity: 0, 36 | cachedFragment: null, 37 | hasRendered: false, 38 | buildFragment: function buildFragment(dom) { 39 | var el0 = dom.createDocumentFragment(); 40 | var el1 = dom.createElement("div"); 41 | dom.setAttribute(el1, "class", "package1"); 42 | var el2 = dom.createTextNode("\n Package 1\n "); 43 | dom.appendChild(el1, el2); 44 | var el2 = dom.createComment(""); 45 | dom.appendChild(el1, el2); 46 | var el2 = dom.createTextNode("\n"); 47 | dom.appendChild(el1, el2); 48 | dom.appendChild(el0, el1); 49 | var el1 = dom.createTextNode("\n"); 50 | dom.appendChild(el0, el1); 51 | var el1 = dom.createComment(""); 52 | dom.appendChild(el0, el1); 53 | return el0; 54 | }, 55 | buildRenderNodes: function buildRenderNodes(dom, fragment, contextualElement) { 56 | var morphs = new Array(2); 57 | morphs[0] = dom.createMorphAt(dom.childAt(fragment, [0]), 1, 1); 58 | morphs[1] = dom.createMorphAt(fragment, 2, 2, contextualElement); 59 | dom.insertBoundary(fragment, null); 60 | return morphs; 61 | }, 62 | statements: [["content", "model.modelProperty", ["loc", [null, [3, 2], [3, 25]]]], ["content", "outlet", ["loc", [null, [5, 0], [5, 10]]]]], 63 | locals: [], 64 | templates: [] 65 | }; 66 | })()); 67 | }); 68 | define("package1/templates/package1/nested", ["exports"], function (exports) { 69 | exports["default"] = Ember.HTMLBars.template((function () { 70 | return { 71 | meta: { 72 | "revision": "Ember@1.13.13", 73 | "loc": { 74 | "source": null, 75 | "start": { 76 | "line": 1, 77 | "column": 0 78 | }, 79 | "end": { 80 | "line": 1, 81 | "column": 32 82 | } 83 | }, 84 | "moduleName": "package1/templates/package1/nested.hbs" 85 | }, 86 | arity: 0, 87 | cachedFragment: null, 88 | hasRendered: false, 89 | buildFragment: function buildFragment(dom) { 90 | var el0 = dom.createDocumentFragment(); 91 | var el1 = dom.createTextNode("From the correct nested template"); 92 | dom.appendChild(el0, el1); 93 | return el0; 94 | }, 95 | buildRenderNodes: function buildRenderNodes() { 96 | return []; 97 | }, 98 | statements: [], 99 | locals: [], 100 | templates: [] 101 | }; 102 | })()); 103 | }); 104 | /* jshint ignore:start */ 105 | 106 | 107 | 108 | /* jshint ignore:end */ 109 | 110 | /* jshint ignore:start */ 111 | 112 | define('dummy/config/environment', ['ember'], function(Ember) { 113 | var prefix = 'dummy'; 114 | /* jshint ignore:start */ 115 | 116 | try { 117 | var metaName = prefix + '/config/environment'; 118 | var rawConfig = Ember['default'].$('meta[name="' + metaName + '"]').attr('content'); 119 | var config = JSON.parse(unescape(rawConfig)); 120 | 121 | return { 'default': config }; 122 | } 123 | catch(err) { 124 | throw new Error('Could not read config from meta tag with name "' + metaName + '".'); 125 | } 126 | 127 | /* jshint ignore:end */ 128 | 129 | }); 130 | 131 | /* jshint ignore:end */ 132 | 133 | /* jshint ignore:start */ 134 | 135 | 136 | 137 | /* jshint ignore:end */ 138 | //# sourceMappingURL=package1.map 139 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_package2_css.approved.txt: -------------------------------------------------------------------------------- 1 | .package2 { 2 | background: black; } 3 | 4 | /*# sourceMappingURL=package2.css.map */ 5 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_package2_js.approved.txt: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | /* jshint ignore:start */ 4 | 5 | 6 | 7 | /* jshint ignore:end */ 8 | 9 | define('package2/routes/package2', ['exports', 'ember'], function (exports, _ember) { 10 | exports['default'] = _ember['default'].Route.extend({ 11 | debug: 'from-package2' 12 | }); 13 | }); 14 | define("package2/templates/package2", ["exports"], function (exports) { 15 | exports["default"] = Ember.HTMLBars.template((function () { 16 | return { 17 | meta: { 18 | "revision": "Ember@1.13.13", 19 | "loc": { 20 | "source": null, 21 | "start": { 22 | "line": 1, 23 | "column": 0 24 | }, 25 | "end": { 26 | "line": 4, 27 | "column": 0 28 | } 29 | }, 30 | "moduleName": "package2/templates/package2.hbs" 31 | }, 32 | arity: 0, 33 | cachedFragment: null, 34 | hasRendered: false, 35 | buildFragment: function buildFragment(dom) { 36 | var el0 = dom.createDocumentFragment(); 37 | var el1 = dom.createElement("div"); 38 | dom.setAttribute(el1, "class", "package2"); 39 | var el2 = dom.createTextNode("\n Package 2\n"); 40 | dom.appendChild(el1, el2); 41 | dom.appendChild(el0, el1); 42 | var el1 = dom.createTextNode("\n"); 43 | dom.appendChild(el0, el1); 44 | return el0; 45 | }, 46 | buildRenderNodes: function buildRenderNodes() { 47 | return []; 48 | }, 49 | statements: [], 50 | locals: [], 51 | templates: [] 52 | }; 53 | })()); 54 | }); 55 | /* jshint ignore:start */ 56 | 57 | 58 | 59 | /* jshint ignore:end */ 60 | 61 | /* jshint ignore:start */ 62 | 63 | define('dummy/config/environment', ['ember'], function(Ember) { 64 | var prefix = 'dummy'; 65 | /* jshint ignore:start */ 66 | 67 | try { 68 | var metaName = prefix + '/config/environment'; 69 | var rawConfig = Ember['default'].$('meta[name="' + metaName + '"]').attr('content'); 70 | var config = JSON.parse(unescape(rawConfig)); 71 | 72 | return { 'default': config }; 73 | } 74 | catch(err) { 75 | throw new Error('Could not read config from meta tag with name "' + metaName + '".'); 76 | } 77 | 78 | /* jshint ignore:end */ 79 | 80 | }); 81 | 82 | /* jshint ignore:end */ 83 | 84 | /* jshint ignore:start */ 85 | 86 | 87 | 88 | /* jshint ignore:end */ 89 | //# sourceMappingURL=package2.map 90 | -------------------------------------------------------------------------------- /approvals/a_dev_build.contains_vendor_css.approved.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /approvals/config.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var reporters = [ 3 | "BeyondCompare", 4 | "opendiff", 5 | "p4merge", 6 | "tortoisemerge", 7 | "gitdiff" 8 | ]; 9 | 10 | if (process.env.CI) { 11 | reporters = ['gitdiff']; 12 | } 13 | 14 | module.exports = {reporters}; 15 | -------------------------------------------------------------------------------- /approvals/test.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | /* global before, describe, it */ 3 | const approvals = require('approvals'); 4 | const config = require('./config'); 5 | const fs = require('fs'); 6 | const childProcess = require('child_process'); 7 | const cheerio = require('cheerio'); 8 | const assert = require('assert'); 9 | 10 | const basePath = 'tmp/approvals/'; 11 | approvals.configure(config); 12 | approvals.mocha(); 13 | 14 | if (process.env['EMBER_TRY_SCENARIO'] && process.env['EMBER_TRY_SCENARIO'] !== 'ember-1-13') { 15 | return; 16 | } 17 | 18 | before(function () { 19 | this.verifyFileContent = function (fileName) { 20 | this.verify(fs.readFileSync(fileName)); 21 | }; 22 | }); 23 | describe('a dev build', function () { 24 | const outputPath = `${basePath}/dev-build/`; 25 | before(function() { 26 | this.timeout(30000); 27 | childProcess.execSync(`ember build --environment development --output-path ${outputPath}`); 28 | }); 29 | it('contains an index file', function () { 30 | this.verifyFileContent(`${outputPath}/index.html`); 31 | }); 32 | 33 | var assetsToVerify = ['package1.js', 34 | 'package1.css', 35 | 'package2.js', 36 | 'package2.css', 37 | 'dummy.js', 38 | 'dummy.css', 39 | 'vendor.js', 40 | 'vendor.css',]; 41 | assetsToVerify.forEach(function (file) { 42 | it(`contains ${file}`, function () { 43 | this.verifyFileContent(`${outputPath}/assets/${file}`); 44 | }); 45 | }); 46 | }); 47 | 48 | describe('a prd build', function () { 49 | const outputPath = `${basePath}/prd-build/`; 50 | before(function() { 51 | this.timeout(60000); 52 | childProcess.execSync(`ember build --environment production --output-path ${outputPath}`); 53 | }); 54 | it('contains an index file with fingerprinted assets', function () { 55 | const html = fs.readFileSync(`${outputPath}/index.html`, 'utf8'); 56 | console.log(html); 57 | const $ = cheerio.load(html); 58 | const scripts = $('script'); 59 | console.log(scripts); 60 | assert.equal(2, scripts.length, 'Should contain 2 script tags'); 61 | assert.ok(/assets\/vendor-.*\.js/.exec($(scripts[0]).attr('src'))); 62 | assert.ok(/assets\/dummy-.*\.js/.exec($(scripts[1]).attr('src'))); 63 | 64 | const styles = $('link'); 65 | assert.equal(2, styles.length, 'Should contain 2 link tags'); 66 | assert.ok(/assets\/vendor-.*\.css/.exec($(styles[0]).attr('href'))); 67 | assert.ok(/assets\/dummy-.*\.css/.exec($(styles[1]).attr('href'))); 68 | }); 69 | }); 70 | -------------------------------------------------------------------------------- /blueprints/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "console" 4 | ], 5 | "strict": false 6 | } 7 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/app/resolver.js: -------------------------------------------------------------------------------- 1 | export { default } from 'ember-cli-bundle-loader/resolver'; 2 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/app/router.js: -------------------------------------------------------------------------------- 1 | import LazyRouter from 'ember-cli-bundle-loader/lazy-router'; 2 | import config from './config/environment'; 3 | 4 | const Router = LazyRouter.extend({ 5 | location: config.locationType 6 | }); 7 | 8 | Router.map(function() { 9 | 10 | }); 11 | 12 | export default Router; 13 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/config/bundles.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | module.exports = [ 3 | // { 4 | // name: 'package1', 5 | // // [WIP] 6 | // // This will be used later to concat packages into a single bundle. Right now there 7 | // // is a one-one mapping in config, but when we lazy-load we think of bundles not packages 8 | // packages: ['package1'], 9 | // // Specifies the routes that a particular bundle can handle. This follows the same 10 | // // routeName used by the router.router and applicationController.routeName 11 | // // for example, 'application', 'index', 'loading', 'package1', 'package1.nested', 'anotherRoute.nested.index' 12 | // // we use a regular expression to match, if a package handles all the nested routes 13 | // // you can use ['topLevelRoute'], if you need to handle only nesting, then be more specific ['topLevelRoute.nested'] 14 | // // Keep in mind that we use a RegEx, so you normally want to do a starts with (^) to avoid matchin otherRoute.package1 15 | // routeNames: ['^package1'], 16 | // // Sometimes a bundle can have exceptions, it matches the routeNames above, but does NOT match 17 | // // any of the blackalistedRouteNames. For example, you may have a bundle that handles anything that is not 18 | // // already handled by other bundles. Maybe your admin bundle handles routeNames: ['^admin'], then your second 19 | // // bundle handles any route exception ^admin (routeNames: ['.'] and blacklistedRouteNames: ['^admin']) 20 | // blacklistedRouteNames: [''] 21 | // // Bundles can have dependencies, which means that before loading package1 we need to load package2 22 | // // dependencies can be static and explicit (e.g. an import statement evaluated as part of initial code execution) or dynamic 23 | // // required by ember or your code, but we need to make them sync to avoid blocking a second time or make sure that Ember sync 24 | // // operations work like a service depedency. 25 | // // [WIP] 26 | // // dependsOn: ['package2'] 27 | // }, { 28 | // name: 'package2', 29 | // packages: ['package2'], 30 | // routeNames: ['^package2'] 31 | // } 32 | ]; 33 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/config/package-names.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var fs = require('fs'), 3 | path = require('path'); 4 | 5 | function getDirectories(srcpath) { 6 | return fs.readdirSync(srcpath).filter(function (file) { 7 | return fs.statSync(path.join(srcpath, file)).isDirectory(); 8 | }); 9 | } 10 | 11 | var packagesDir = path.join(__dirname, '..', 'packages'); 12 | module.exports = getDirectories(packagesDir); 13 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var EmberAppWithPackages = require('ember-cli-bundle-loader/lib/broccoli/ember-app-with-packages'); 3 | 4 | module.exports = function (defaults) { 5 | var emberAppWithPackages = new EmberAppWithPackages(defaults, { 6 | sharedBuildConfig: { 7 | // This configuration applies to the app config as well as all the packages 8 | }, 9 | appBuildConfig: { 10 | // This configuration applies to the app only and is different than the configuration used by packages 11 | }, 12 | packagesBuildConfig: { 13 | // This configuration applies to the app only and is different than the configuration used by the app 14 | } 15 | }); 16 | 17 | // Use `emberAppWithPackages.import` to add additional libraries to the generated 18 | // output files. 19 | // 20 | // If you need to use different assets in different 21 | // environments, specify an object as the first parameter. That 22 | // object's keys should be the environment name and the values 23 | // should be the asset to use in that environment. 24 | // 25 | // If the library that you are including contains AMD or ES6 26 | // modules that you would like to import into your application 27 | // please specify an object with the list of modules as keys 28 | // along with the exports of each module as its value. 29 | 30 | return emberAppWithPackages.toTree(); 31 | }; 32 | -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/files/packages/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/ember-cli-bundle-loader/files/packages/.gitkeep -------------------------------------------------------------------------------- /blueprints/ember-cli-bundle-loader/index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | module.exports = { 3 | description: 'Adds configuration files required by ember-cli-bundle-loader', 4 | normalizeEntityName: function() { 5 | // Normalize and validate entity name here. 6 | // The entitiy name isn't required, but ember-cli crashes without it 7 | return 'irrelevant'; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/components/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/controllers/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/helpers/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/models/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/resolvers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/resolvers/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/routes/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /blueprints/package/files/packages/__name__/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/blueprints/package/files/packages/__name__/templates/.gitkeep -------------------------------------------------------------------------------- /blueprints/package/index.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var fs = require('fs'), 3 | path = require('path'); 4 | 5 | module.exports = { 6 | description: 'Generates a new package that can be bundled and lazy loaded', 7 | 8 | beforeInstall: function (options) { 9 | var packagesDir = path.join(options.target, 'packages'); 10 | if (!fs.existsSync(packagesDir)) { 11 | fs.mkdirSync(path.join(options.target, 'packages')); 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-cli-bundle-loader", 3 | "dependencies": { 4 | "ember": "~1.13.0", 5 | "ember-cli-shims": "0.1.0", 6 | "ember-cli-test-loader": "0.2.2", 7 | "ember-qunit-notifications": "0.1.0" 8 | }, 9 | "resolutions": { 10 | "ember": "~1.13.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /config/deploy.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 3 | module.exports = function(deployTarget) { 4 | var ENV = { 5 | build: {} 6 | // include other plugin configuration that applies to all deploy targets here 7 | }; 8 | 9 | if (deployTarget === 'development') { 10 | ENV.build.environment = 'development'; 11 | // configure other plugins for development deploy target here 12 | } 13 | 14 | if (deployTarget === 'staging') { 15 | ENV.build.environment = 'production'; 16 | // configure other plugins for staging deploy target here 17 | } 18 | 19 | if (deployTarget === 'production') { 20 | ENV.build.environment = 'production'; 21 | // configure other plugins for production deploy target here 22 | } 23 | 24 | // Note: if you need to build some configuration asynchronously, you can return 25 | // a promise that resolves with the ENV object instead of returning the 26 | // ENV object synchronously. 27 | return ENV; 28 | }; 29 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | module.exports = { 3 | scenarios: [ 4 | { 5 | name: 'ember-1-13', 6 | bower: { 7 | dependencies: { 8 | 'ember': '~1.13.0' 9 | }, 10 | resolutions: { 11 | 'ember': '~1.13.0' 12 | } 13 | } 14 | }, 15 | { 16 | name: 'ember-lts-2.4', 17 | bower: { 18 | dependencies: { 19 | 'ember': 'components/ember#lts-2-4', 20 | 'ember-cli-shims': '0.1.3' 21 | }, 22 | resolutions: { 23 | 'ember': 'lts-2-4' 24 | } 25 | }, 26 | npm: { 27 | devDependencies: { 28 | 'ember-source': null 29 | } 30 | } 31 | }, 32 | { 33 | name: 'ember-lts-2.8', 34 | bower: { 35 | dependencies: { 36 | 'ember': 'components/ember#lts-2-8', 37 | 'ember-cli-shims': '0.1.3' 38 | }, 39 | resolutions: { 40 | 'ember': 'lts-2-8' 41 | } 42 | }, 43 | npm: { 44 | devDependencies: { 45 | 'ember-source': null 46 | } 47 | } 48 | }, 49 | { 50 | name: 'ember-release', 51 | bower: { 52 | dependencies: { 53 | 'ember': 'components/ember#release' 54 | }, 55 | resolutions: { 56 | 'ember': 'release' 57 | } 58 | } 59 | }, 60 | { 61 | name: 'ember-beta', 62 | bower: { 63 | dependencies: { 64 | 'ember': 'components/ember#beta' 65 | }, 66 | resolutions: { 67 | 'ember': 'beta' 68 | } 69 | } 70 | }, 71 | { 72 | name: 'ember-canary', 73 | bower: { 74 | dependencies: { 75 | 'ember': 'components/ember#canary' 76 | }, 77 | resolutions: { 78 | 'ember': 'canary' 79 | } 80 | } 81 | } 82 | ] 83 | }; 84 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | 'use strict'; 3 | 4 | module.exports = function(/* environment, appConfig */) { 5 | return { }; 6 | }; 7 | -------------------------------------------------------------------------------- /config/release.js: -------------------------------------------------------------------------------- 1 | /* jshint node:true */ 2 | // var RSVP = require('rsvp'); 3 | 4 | // For details on each option run `ember help release` 5 | module.exports = { 6 | // local: true, 7 | // remote: 'some_remote', 8 | // annotation: "Release %@", 9 | // message: "Bumped version to %@", 10 | // manifest: [ 'package.json', 'bower.json', 'someconfig.json' ], 11 | publish: true, 12 | // strategy: 'date', 13 | // format: 'YYYY-MM-DD', 14 | // timezone: 'America/Los_Angeles', 15 | // 16 | // beforeCommit: function(project, versions) { 17 | // return new RSVP.Promise(function(resolve, reject) { 18 | // // Do custom things here... 19 | // }); 20 | // } 21 | }; 22 | -------------------------------------------------------------------------------- /ember-cli-build.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var EmberAppWithPackages = require('./lib/broccoli/ember-app-with-packages'); 3 | 4 | module.exports = function (defaults) { 5 | var emberAppWithPackages = new EmberAppWithPackages(defaults, { 6 | sharedBuildConfig: { 7 | // This configuration applies to the app config as well as all the packages 8 | }, 9 | appBuildConfig: { 10 | // This configuration applies to the app only and is different than the configuration used by packages 11 | }, 12 | packagesBuildConfig: { 13 | // This configuration applies to the app only and is different than the configuration used by the app 14 | } 15 | }); 16 | 17 | // Use `emberAppWithPackages.import` to add additional libraries to the generated 18 | // output files. 19 | // 20 | // If you need to use different assets in different 21 | // environments, specify an object as the first parameter. That 22 | // object's keys should be the environment name and the values 23 | // should be the asset to use in that environment. 24 | // 25 | // If the library that you are including contains AMD or ES6 26 | // modules that you would like to import into your application 27 | // please specify an object with the list of modules as keys 28 | // along with the exports of each module as its value. 29 | 30 | return emberAppWithPackages.toTree(); 31 | }; 32 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | 'use strict'; 3 | var VersionChecker = require('ember-cli-version-checker'); 4 | module.exports = { 5 | name: 'ember-cli-bundle-loader', 6 | included: function (app) { 7 | this._super.included(app); 8 | 9 | var checker = new VersionChecker(this); 10 | var emberChecker = checker.for('ember', 'bower'); 11 | if (emberChecker.lt('2.3.0')) { 12 | checker.for('ember-getowner-polyfill', 'npm').assertAbove('1.2.1'); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /lib/broccoli/ember-app-with-packages.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var EmberApp = require('ember-cli/lib/broccoli/ember-app'), 3 | EmberAddon = require('ember-cli/lib/broccoli/ember-addon'), 4 | Funnel = require('broccoli-funnel'), 5 | mergeTrees = require('broccoli-merge-trees'), 6 | AssetRev = require('broccoli-asset-rev'), 7 | merge = require('merge-defaults'), 8 | getBundleConfiguration = require('../utils/get-bundle-configuration'); 9 | 10 | module.exports = EmberAppWithPackages; 11 | 12 | function EmberAppWithPackages(defaults, options) { 13 | var isAddon = !!(defaults.project.pkg["ember-addon"] && defaults.project.pkg["ember-addon"].configPath), 14 | sharedBuildConfig = { 15 | // TODO: re-enable jshint once it's actually working fine, for now it just slows down the build 16 | // and running `ember test` it only jshints boot, but not the packages. We'll rely an npm script 17 | // for now 18 | hinting: false, 19 | fingerprint: { 20 | // Disabling here since we do it at the end for *all* the assets 21 | enabled: false, 22 | } 23 | }, 24 | appBuildConfig = { 25 | // Instructions: Add your custom config for the boot app here 26 | appTreesBasePath: 'app' 27 | }, 28 | packagesBuildConfig = { 29 | tests: false, 30 | vendorFiles: { 31 | // Avoids serving the same dependency twice. List extracted from ember-cli/lib/broccoli/ember-app.js#_initVendorFiles 32 | 'jquery.js': null, 33 | 'handlebars.js': null, 34 | 'ember.js': null, 35 | 'loader.js': null, 36 | 37 | // We need to leave this as is. 38 | // 'ember-testing.js': null, 39 | 'app-shims.js': null, 40 | 'ember-resolver.js': null, 41 | 'ember-data': null, // do this for boot as well if you don't use ember-data 42 | 'ember-cli-app-version': null, 43 | 'vendor-suffix': null, 44 | 'ember-load-initializers.js': null, 45 | 'ember-debug-handlers-polyfill': null, 46 | 'ember-cli-deprecation-workflow': null, 47 | 'ic-ajax': null 48 | } 49 | }, 50 | basePath = isAddon ? 'tests/dummy/' : '', 51 | packageNames = [], 52 | bundles; 53 | 54 | if (options) { 55 | sharedBuildConfig = merge(options.sharedBuildConfig || {}, sharedBuildConfig); 56 | appBuildConfig = merge(options.appBuildConfig || {}, appBuildConfig); 57 | packagesBuildConfig = merge(options.packagesBuildConfig || {}, packagesBuildConfig); 58 | } 59 | packageNames = require(defaults.project.root + '/' + basePath + '/config/package-names'); 60 | 61 | if (isAddon) { 62 | // We're inside an addon, so use an Addon constructor for the main app to get the right paths to tests/dummy/index and other likely other places 63 | this.bootApp = new EmberAddon(defaults, sharedBuildConfig, appBuildConfig); 64 | } else { 65 | var configWithTrees = { 66 | trees: { 67 | app: new Funnel(basePath + appBuildConfig.appTreesBasePath), 68 | styles: new Funnel(appBuildConfig.appTreesBasePath + '/styles'), 69 | templates: new Funnel(appBuildConfig.appTreesBasePath + '/templates') 70 | } 71 | }; 72 | this.bootApp = new EmberApp(configWithTrees, defaults, sharedBuildConfig, appBuildConfig); 73 | } 74 | 75 | // ember-cli only configures babel plugins once, so subsequent calls to new EmberApp in the same 76 | // process won't add it again, so we need to add it manually for packages. 77 | defaults.babel = defaults.babel || appBuildConfig.babel; 78 | defaults.babel.plugins = defaults.babel.plugins || appBuildConfig.babel.plugins; 79 | 80 | this.bootApp.contentFor = function(config, match, type) { 81 | if (!bundles) { 82 | bundles = require(defaults.project.root + '/' + basePath + '/config/bundles'); 83 | bundles = getBundleConfiguration(bundles, packageNames, config); 84 | } 85 | var content = []; 86 | if (type === 'app-boot') { 87 | content.push('define(\'ember-cli-bundle-loader/config/bundles\', function() { '); 88 | content.push(' return ' + JSON.stringify(bundles)); 89 | content.push('});'); 90 | 91 | content.push('define(\'ember-cli-bundle-loader/config/package-names\', function() { '); 92 | content.push(' return ' + JSON.stringify(packageNames)); 93 | content.push('});'); 94 | 95 | content = content.concat( 96 | EmberApp.prototype.contentFor.call(this, config, match, type)); 97 | return content.join('\n'); 98 | } else { 99 | return EmberApp.prototype.contentFor.call(this, config, match, type); 100 | } 101 | }; 102 | 103 | var perPackageConfigFactory = options.perPackageConfig || function () { 104 | return {}; 105 | }; 106 | 107 | // TODO: check if we need to call app.toTree before *creating* the apps or only before toTree'ing them 108 | // packages subsequent calls to EmberApp() constructor must come after the main app.toTree 109 | // in order for the addons to run postprocessTree correctly 110 | this.packagesApplications = packageNames.map(function(packageName) { 111 | // packages export their own js file and are intended to distribute the code-base. 112 | var perPackageConfig = perPackageConfigFactory(packageName); 113 | perPackageConfig = merge({}, perPackageConfig, {appTreesBasePath: 'packages/' + packageName}); 114 | 115 | var packageConfig = { 116 | name: packageName, 117 | outputPaths: { 118 | app: { 119 | js: '/assets/' + packageName + '.js', 120 | css: { 121 | app: '/assets/' + packageName + '.css' 122 | } 123 | }, 124 | }, 125 | trees: { 126 | app: mergeTrees([ 127 | // The index.html is required, so we funnel it here, but return it unmodified 128 | // below (see package.index) to avoid running ConfigReplace 129 | new Funnel(basePath + appBuildConfig.appTreesBasePath, { files: ['index.html'] }), 130 | new Funnel(basePath + perPackageConfig.appTreesBasePath) 131 | ]), 132 | styles: new Funnel(basePath + perPackageConfig.appTreesBasePath + '/styles'), 133 | templates: new Funnel(basePath + perPackageConfig.appTreesBasePath + '/templates') 134 | } 135 | }, 136 | package = new EmberApp(defaults, packageConfig, sharedBuildConfig, packagesBuildConfig, perPackageConfig); 137 | 138 | // Prevent packages from creating their own Ember Application 139 | package.contentFor = function(config, match, type) { 140 | if (type === 'app-boot' || type === 'app-config') { 141 | return ''; 142 | } else { 143 | return EmberApp.prototype.contentFor.call(this, config, match, type); 144 | } 145 | }; 146 | 147 | // Only boot includes addon's code 148 | package.addonTreesFor = function(type) { 149 | // TODO: consider excluding addon, addon-test-suppor, public, styles, test-support, vendor (or all) 150 | if (type === 'app' || type === 'templates') { 151 | return []; 152 | } else { 153 | return EmberApp.prototype.addonTreesFor.call(this, type); 154 | } 155 | }; 156 | return package; 157 | }); 158 | } 159 | 160 | EmberAppWithPackages.prototype.import = function(asset, options) { 161 | this.bootApp.import(asset, options); 162 | }; 163 | 164 | EmberAppWithPackages.prototype.toTree = function (additionalTrees) { 165 | var env = process.env.EMBER_ENV; 166 | var movedPackagesApplicationTrees = this.packagesApplications.map(function(package) { 167 | var packageTree = package.toTree(); 168 | return new Funnel(packageTree); 169 | }); 170 | var bootAppTree = this.bootApp.toTree(); 171 | var fingerPrintOptions = Object.assign({}, this.bootApp.options.fingerprint); 172 | 173 | var allTrees = mergeTrees(movedPackagesApplicationTrees.concat([bootAppTree/*, publicVendorFiles*/]).concat(additionalTrees || []), { 174 | overwrite: true, 175 | annotation: 'TreeMerger (allTrees - App+Packages)' 176 | }); 177 | 178 | if (env === 'production') { 179 | // AssetRev has three passes, we want to do bootAppName.js on the third pass since it contains references to other JS files 180 | fingerPrintOptions.filesForThirdPass = [this.bootApp.name + '.js']; 181 | allTrees = new AssetRev(allTrees, fingerPrintOptions); 182 | } 183 | 184 | return allTrees; 185 | }; 186 | -------------------------------------------------------------------------------- /lib/utils/get-bundle-configuration.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | 3 | var flatten = function (list) { 4 | return list.reduce(function (a, b) { 5 | return a.concat(Array.isArray(b) ? flatten(b) : b); 6 | }, []); 7 | }; 8 | 9 | var getDefaultUrls = function (name, rootURL) { 10 | return [rootURL + 'assets/' + name + '.js', rootURL + 'assets/' + name + '.css']; 11 | }; 12 | 13 | var generateBundleWithDefaults = function generateBundleWithDefaults (name, baseBundle, rootURL) { 14 | return { 15 | name: name, 16 | packages: baseBundle.packages || [name], 17 | urls: baseBundle.urls || getDefaultUrls(name, rootURL), 18 | routeNames: baseBundle.routeNames || ['^' + name], 19 | dependsOn: baseBundle.dependsOn || [], 20 | blacklistedRouteNames: baseBundle.blacklistedRouteNames || [], 21 | }; 22 | }; 23 | 24 | /*** 25 | * Returns the list of all the bundles. If a bundle isn't defined in config/bundles.js 26 | * a default is inferred based on the package-names where there is a one to one package-bundle, 27 | * the bundle has no dependencies and we load from the default URLs that Ember specified 28 | */ 29 | module.exports = function (bundles, packageNames, config) { 30 | var rootURL = (config && config.rootURL) || ''; 31 | 32 | var bundlesWithDefaults = bundles.map(bundle => 33 | generateBundleWithDefaults(bundle.name, bundle, rootURL)); 34 | var usedPackagesNames = flatten(bundlesWithDefaults.map(bundle =>bundle.packages)); 35 | var packageNamesWithoutBundles = packageNames.filter(name => 36 | usedPackagesNames.indexOf(name) === -1); 37 | 38 | var bundlesForMissingPackages = packageNamesWithoutBundles.map(name => 39 | generateBundleWithDefaults(name, {}, rootURL)); 40 | 41 | return bundlesWithDefaults.concat(bundlesForMissingPackages); 42 | }; 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-cli-bundle-loader", 3 | "version": "0.5.0", 4 | "private": false, 5 | "description": "The default blueprint for ember-cli addons.", 6 | "directories": { 7 | "doc": "doc", 8 | "test": "tests" 9 | }, 10 | "scripts": { 11 | "build": "ember build", 12 | "start": "ember server", 13 | "test": "npm run jshint && npm run node-tests && npm run approvals", 14 | "jshint": "./node_modules/.bin/jshint addon/ app/ approvals/ blueprints/**/index.js config/ lib/ tests/", 15 | "approvals": "node_modules/mocha/bin/mocha approvals/test.js", 16 | "node-tests": "node_modules/mocha/bin/mocha tests-node/test.js", 17 | "ember-tests": "ember test" 18 | }, 19 | "repository": "MiguelMadero/ember-cli-bundle-loader", 20 | "engines": { 21 | "node": ">= 4.4.0" 22 | }, 23 | "author": "", 24 | "license": "MIT", 25 | "devDependencies": { 26 | "approvals": "1.2.0", 27 | "broccoli-asset-rev": "git+https://github.com/zenefits/broccoli-asset-rev#v3.0.0-zenefits.0", 28 | "cheerio": "^0.22.0", 29 | "ember-ajax": "0.7.1", 30 | "ember-cli": "2.4.2", 31 | "ember-cli-dependency-checker": "^1.2.0", 32 | "ember-cli-deploy": "1.0.0-beta.1", 33 | "ember-cli-deploy-build": "0.1.1", 34 | "ember-cli-deploy-git": "1.0.0", 35 | "ember-cli-htmlbars-inline-precompile": "^0.3.1", 36 | "ember-cli-inject-live-reload": "^1.3.1", 37 | "ember-cli-qunit": "3.0.0-beta.2", 38 | "ember-cli-release": "v1.0.0-beta.2", 39 | "ember-cli-sass": "5.3.0", 40 | "ember-cli-sri": "^2.1.0", 41 | "ember-cli-test-loader": "1.1.0", 42 | "ember-cli-uglify": "^1.2.0", 43 | "ember-cli-version-checker": "1.2.0", 44 | "ember-disable-prototype-extensions": "^1.1.0", 45 | "ember-disable-proxy-controllers": "^1.0.1", 46 | "ember-export-application-global": "^1.0.4", 47 | "ember-getowner-polyfill": "~1.2.2", 48 | "ember-load-initializers": "^0.5.0", 49 | "ember-qunit-nice-errors": "1.1.2", 50 | "ember-resolver": "^2.0.3", 51 | "ember-sinon": "0.5.0", 52 | "ember-sinon-qunit": "1.4.0", 53 | "ember-try": "^0.2.1", 54 | "jshint": "^2.9.1", 55 | "loader.js": "4.0.9", 56 | "mocha": "^2.4.5" 57 | }, 58 | "keywords": [ 59 | "ember-addon" 60 | ], 61 | "dependencies": { 62 | "broccoli-funnel": "1.0.1", 63 | "broccoli-merge-trees": "^1.1.1", 64 | "ember-cli-babel": "^5.1.5", 65 | "ember-cli-htmlbars": "^1.0.1", 66 | "ember-get-config": "0.0.2", 67 | "merge-defaults": "^0.2.1" 68 | }, 69 | "ember-addon": { 70 | "configPath": "tests/dummy/config" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /testem.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | module.exports = { 3 | "framework": "qunit", 4 | "test_page": "tests/index.html?hidepassed", 5 | "disable_watching": true, 6 | "launch_in_ci": [ 7 | "PhantomJS" 8 | ], 9 | "launch_in_dev": [ 10 | "PhantomJS", 11 | "Chrome" 12 | ] 13 | }; 14 | -------------------------------------------------------------------------------- /tests-node/test.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | /* global describe, it */ 3 | var assert = require('assert'); 4 | var getBundleConfiguration = require('../lib/utils/get-bundle-configuration'); 5 | var bundles = [{ 6 | name: 'package1', 7 | packages: ['package1'], 8 | urls: ['assets/package1.js','assets/package1.css'], 9 | routeNames: ['^package1'], 10 | dependsOn: ['package2'], 11 | blacklistedRouteNames: ['^blacklistedRouteName'] 12 | }]; 13 | 14 | if (process.env['EMBER_TRY_SCENARIO'] && process.env['EMBER_TRY_SCENARIO'] !== 'ember-1-13') { 15 | return; 16 | } 17 | 18 | describe('getBundleConfiguration', function () { 19 | it('is based on bundles', function () { 20 | const newBundles = getBundleConfiguration(bundles, []); 21 | assert.equal(newBundles[0].name, 'package1'); 22 | assert.deepEqual(newBundles, bundles); 23 | }); 24 | 25 | it('creates a default bundle structure based on packageNames if configBundles aren\t present', function () { 26 | const newBundles = getBundleConfiguration([], ['my-package']); 27 | assert.deepEqual(newBundles, [{ 28 | name: 'my-package', 29 | packages: ['my-package'], 30 | urls: ['assets/my-package.js', 'assets/my-package.css'], 31 | routeNames: ['^my-package'], 32 | dependsOn: [], 33 | blacklistedRouteNames: [], 34 | }]); 35 | }); 36 | 37 | it('adds all missing packageNames to the bundle, creating defaults for the packages not currently present', function () { 38 | const newConfig = getBundleConfiguration(bundles.slice(), ['my-package']); 39 | assert.deepEqual(newConfig, bundles.concat([{ 40 | name: 'my-package', 41 | packages: ['my-package'], 42 | routeNames: ['^my-package'], 43 | urls: ['assets/my-package.js', 'assets/my-package.css'], 44 | dependsOn: [], 45 | blacklistedRouteNames: [], 46 | }])); 47 | }); 48 | 49 | it('adds default URLs for packages without URLs', function () { 50 | const bundleConfig = [{ 51 | name: 'my-package', 52 | routeNames: ['^irrelevant'], 53 | packages: ['my-package'], 54 | // urls: ['assets/my-package.js', 'assets/my-package.css'], 55 | }]; 56 | const newConfig = getBundleConfiguration(bundleConfig, []); 57 | assert.deepEqual(newConfig, [{ 58 | name: 'my-package', 59 | routeNames: ['^irrelevant'], 60 | packages: ['my-package'], 61 | urls: ['assets/my-package.js', 'assets/my-package.css'], 62 | dependsOn: [], 63 | blacklistedRouteNames: [], 64 | }]); 65 | }); 66 | 67 | it('default URLs include the rootURL based on the config', function () { 68 | const bundleConfig = [{ 69 | name: 'my-package', 70 | packages: ['my-package'], 71 | routeNames: ['^irrelevant'], 72 | // urls: ['assets/my-package.js', 'assets/my-package.css'], 73 | }]; 74 | const newConfig = getBundleConfiguration(bundleConfig, [], {rootURL: '/static/client-app/'}); 75 | assert.deepEqual(newConfig, [{ 76 | name: 'my-package', 77 | packages: ['my-package'], 78 | routeNames: ['^irrelevant'], 79 | urls: ['/static/client-app/assets/my-package.js', '/static/client-app/assets/my-package.css'], 80 | dependsOn: [], 81 | blacklistedRouteNames: [], 82 | }]); 83 | }); 84 | 85 | it('it uses the default routeNames if none is specified', function () { 86 | const bundleConfig = [{ 87 | name: 'my-package', 88 | packages: ['my-package'], 89 | urls: ['irrelevant.js'], 90 | // routeNames: [....] 91 | }]; 92 | const newConfig = getBundleConfiguration(bundleConfig, []); 93 | assert.deepEqual(newConfig, [{ 94 | name: 'my-package', 95 | packages: ['my-package'], 96 | routeNames: ['^my-package'], 97 | urls: ['irrelevant.js'], 98 | dependsOn: [], 99 | blacklistedRouteNames: [], 100 | }]); 101 | }); 102 | 103 | it('it sets the packages to [bundle.name] if none specified', function () { 104 | const bundleConfig = [{ 105 | name: 'my-package', 106 | // packages: ['my-package'], 107 | routeNames: ['^x'], 108 | urls: ['irrelevant.js'], 109 | }]; 110 | const newConfig = getBundleConfiguration(bundleConfig, []); 111 | assert.deepEqual(newConfig, [{ 112 | name: 'my-package', 113 | packages: ['my-package'], 114 | urls: ['irrelevant.js'], 115 | routeNames: ['^x'], 116 | dependsOn: [], 117 | blacklistedRouteNames: [], 118 | }]); 119 | }); 120 | 121 | it('it doesnt drop dependsOn', function () { 122 | const bundleConfig = [{ 123 | name: 'my-package', 124 | // packages: ['my-package'], 125 | dependsOn: ['another-package'], 126 | urls: [] 127 | }]; 128 | const newConfig = getBundleConfiguration(bundleConfig, []); 129 | assert.deepEqual(newConfig, [{ 130 | name: 'my-package', 131 | packages: ['my-package'], 132 | dependsOn: ['another-package'], 133 | routeNames: ['^my-package'], 134 | urls: [], 135 | blacklistedRouteNames: [], 136 | }]); 137 | }); 138 | }); 139 | 140 | 141 | -------------------------------------------------------------------------------- /tests/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "document", 4 | "window", 5 | "location", 6 | "setTimeout", 7 | "$", 8 | "-Promise", 9 | "define", 10 | "console", 11 | "visit", 12 | "exists", 13 | "fillIn", 14 | "click", 15 | "keyEvent", 16 | "triggerEvent", 17 | "find", 18 | "findWithAssert", 19 | "wait", 20 | "DS", 21 | "andThen", 22 | "currentURL", 23 | "currentPath", 24 | "currentRouteName" 25 | ], 26 | "node": false, 27 | "browser": false, 28 | "boss": true, 29 | "curly": true, 30 | "debug": false, 31 | "devel": false, 32 | "eqeqeq": true, 33 | "evil": true, 34 | "forin": false, 35 | "immed": false, 36 | "laxbreak": false, 37 | "newcap": true, 38 | "noarg": true, 39 | "noempty": false, 40 | "nonew": false, 41 | "nomen": false, 42 | "onevar": false, 43 | "plusplus": false, 44 | "regexp": false, 45 | "undef": true, 46 | "sub": true, 47 | "strict": false, 48 | "white": false, 49 | "eqnull": true, 50 | "esnext": true, 51 | "unused": true 52 | } 53 | -------------------------------------------------------------------------------- /tests/acceptance/a-resolver-test.js: -------------------------------------------------------------------------------- 1 | // NOTE: this file was renamed to a-resolver-test to make sure it’s loaded before other acceptance test. 2 | // This is unfortunate an unnecessary likely it’s the symptom of a larger issue 3 | 4 | /* global require */ 5 | import skipIfPhantom from 'dummy/tests/helpers/skip-if-phantom'; 6 | import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance'; 7 | 8 | moduleForAcceptance('Acceptance | resolver'); 9 | 10 | skipIfPhantom('Can resolve routes from the boot app and packages', function(assert) { 11 | assert.ok(this.application.__container__.lookup('route:application') instanceof 12 | require('dummy/routes/application').default); 13 | 14 | assert.notOk( 15 | this.application.__container__.lookup('route:package1')); 16 | visit('package1'); 17 | andThen(()=> { 18 | const package1 = this.application.__container__.lookup('route:package1'); 19 | const requiredPackage1 = require('package1/routes/package1').default; 20 | assert.ok(package1 instanceof requiredPackage1); 21 | }); 22 | return visit('/'); // reset this so refreshing the browser starts at the root 23 | }); 24 | -------------------------------------------------------------------------------- /tests/acceptance/get-owner-test.js: -------------------------------------------------------------------------------- 1 | /* globals Dummy */ 2 | import Ember from 'ember'; 3 | import { getContainer, getFactory, registerFactory} from 'ember-cli-bundle-loader/utils/get-owner'; 4 | import { test } from 'qunit'; 5 | import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance'; 6 | 7 | moduleForAcceptance('Acceptance | get-owner'); 8 | 9 | function getSomeOwner () { 10 | // NOTE: getting the container like this is a bit cheating 11 | // but we can rely on the global being defined here for testing, 12 | // but no in consumign apps 13 | return Dummy.__container__.lookup('router:main'); 14 | } 15 | 16 | // Replace this with your real tests. 17 | test('can getContainer', function(assert) { 18 | // NOTE: getting the container like this is a bit cheating 19 | // but we can rely on the global being defined here for testing, 20 | // but no in consumign apps 21 | const someOwner = getSomeOwner(); 22 | let container = getContainer(someOwner); 23 | assert.ok(container); 24 | assert.ok(container.lookup); 25 | }); 26 | 27 | test('can getFactory', function(assert) { 28 | const someOwner = getSomeOwner(); 29 | let routeBasic = getFactory(someOwner, 'router:main'); 30 | assert.ok(routeBasic); 31 | }); 32 | 33 | test('can registerFactory', function(assert) { 34 | const someOwner = getSomeOwner(); 35 | const factoryKey = 'router:basic-randome12345'; 36 | 37 | assert.notOk(getFactory(someOwner, factoryKey)); 38 | 39 | registerFactory(someOwner, factoryKey, Ember.Object.extend()); 40 | 41 | assert.ok(getFactory(someOwner, factoryKey)); 42 | }); 43 | -------------------------------------------------------------------------------- /tests/acceptance/loading-substate-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'ember-qunit'; 2 | import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance'; 3 | import { StateForTest } from 'dummy/components/loading-for-test'; 4 | 5 | moduleForAcceptance('Acceptance | loading-substate'); 6 | 7 | test('loading-substate renders while beforeModel promise resolves', function (assert) { 8 | visit('/'); 9 | visit('slow'); 10 | andThen(() => { 11 | assert.ok(StateForTest.hasRendered); 12 | assert.equal(1, find('.slow').length); 13 | }); 14 | return visit('/'); // reset this so refreshing the browser starts at the root 15 | }); 16 | -------------------------------------------------------------------------------- /tests/acceptance/loads-dependent-package-test.js: -------------------------------------------------------------------------------- 1 | import { test } from 'qunit'; 2 | import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; 3 | import ResourceHelper from 'ember-cli-bundle-loader/utils/-resource-helper'; 4 | 5 | moduleForAcceptance('Acceptance | loads dependent package'); 6 | 7 | test('visiting /with-dependency loads the dependent package', function(assert) { 8 | visit('/with-dependency'); 9 | let lazyLoaderService = this.application.__container__.lookup('service:lazy-loader'); 10 | assert.ok(lazyLoaderService.needsLazyLoading('dependent')); 11 | assert.notOk(ResourceHelper.isJavascriptLoaded('assets/dependent.js')); 12 | andThen(function() { 13 | assert.equal(currentURL(), '/with-dependency'); 14 | assert.notOk(lazyLoaderService.needsLazyLoading('dependent')); 15 | assert.ok(ResourceHelper.isJavascriptLoaded('assets/dependent.js')); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tests/acceptance/query-params-test.js: -------------------------------------------------------------------------------- 1 | import skipIfPhantom from 'dummy/tests/helpers/skip-if-phantom'; 2 | import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance'; 3 | 4 | moduleForAcceptance('Acceptance | query-params'); 5 | 6 | skipIfPhantom('Query params are not stored in cache for bundles that are not yet loaded', function(assert) { 7 | visit('/'); 8 | visit('link-target'); 9 | visit('link-target'); 10 | visit('link-source'); 11 | visit('link-target'); 12 | visit('link-source'); 13 | andThen(() => 14 | assert.equal(find('.link-source a').attr('href'), '/link-target?page=2&sort=DESC')); 15 | return visit('/'); // reset this so refreshing the browser starts at the root 16 | }); 17 | -------------------------------------------------------------------------------- /tests/acceptance/services/lazy-loader-test.js: -------------------------------------------------------------------------------- 1 | /* global Dummy, require */ 2 | import Ember from 'ember'; 3 | import { test } from 'ember-qunit'; 4 | import moduleForAcceptance from 'dummy/tests/helpers/module-for-acceptance'; 5 | 6 | moduleForAcceptance('Acceptance', 'lazy-loader'); 7 | 8 | function getSubject () { 9 | return Dummy.__container__.lookup('service:lazy-loader'); 10 | } 11 | 12 | test('loadAssets - promise fails if one of the assets fails to load', function (assert) { 13 | const service = getSubject(); 14 | return service.loadBundle('package-with-wrong-urls').then(()=> 15 | assert.notOk('The promise resolved when it was expected to fail') 16 | ).catch(() => 17 | assert.ok('The promise failed') 18 | ); 19 | }); 20 | 21 | test('getBundleForRouteName based on the configuration', function(assert) { 22 | const service = getSubject(); 23 | const actualBundle = service.getBundleForRouteName('package2'); 24 | 25 | assert.ok(actualBundle); 26 | assert.equal(actualBundle.name, 'package2'); 27 | assert.deepEqual(actualBundle.packages, ['package2']); 28 | }); 29 | 30 | test('getBundleForRouteName based on the configuration blacklist', function(assert) { 31 | const service = getSubject(); 32 | service.setBundles([{ 33 | name: 'blacklist-test', 34 | // This bundle handles everything except the route starting with dashboard 35 | routeNames: ['.'], 36 | blacklistedRouteNames: ['^dashboard', '^index', '^loading'] 37 | }]); 38 | const actualBundle = service.getBundleForRouteName('some-route'); 39 | 40 | assert.ok(actualBundle); 41 | assert.equal(actualBundle.name, 'blacklist-test'); 42 | 43 | assert.notOk(service.getBundleForRouteName('dashboard')); 44 | assert.notOk(service.getBundleForRouteName('index')); 45 | assert.notOk(service.getBundleForRouteName('loading')); 46 | }); 47 | 48 | test('loadBundleForUrl evaluates the loaded code for external packages', function(assert) { 49 | const service = getSubject(); 50 | assert.notOk(service.isBundleLoaded('package2')); 51 | // Normally this would be a separate test, but we don't have an easy way to "unload" code in the browser 52 | assert.notOk( 53 | require._eak_seen['package2/routes/package2']); 54 | 55 | return service.loadBundleForRouteName('package2').then(()=> { 56 | assert.ok(service.isBundleLoaded('package2')); 57 | assert.ok(require._eak_seen['package2/routes/package2']); 58 | }); 59 | }); 60 | 61 | test('_getRouteNamesFromUrl', function(assert) { 62 | const service = getSubject(); 63 | visit('/'); 64 | return andThen(()=> { 65 | assert.equal(service._getRouteNameFromUrl('/'), 'index'); 66 | assert.equal(service._getRouteNameFromUrl('/package2'), 'package2'); 67 | assert.equal(service._getRouteNameFromUrl('/package1/nested/1'), 'package1.nested'); 68 | // If the URL doesn't match any route, simply null 69 | assert.notOk(service._getRouteNameFromUrl('/doesntmatch')); 70 | }); 71 | }); 72 | 73 | test('dependsOn doesnt break if nothing is specified', function(assert) { 74 | const service = getSubject(); 75 | service.setBundles([{ 76 | name: 'bundleA', 77 | urls: ['stuff.js'], 78 | // dependsOn: [], 79 | }]); 80 | 81 | var assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('bundleA'))); 82 | assert.equal(assets.length, 1); 83 | assert.notEqual(assets.indexOf('bundleA'), -1); 84 | }); 85 | 86 | test('dependsOn can handle a simple dependency', function(assert) { 87 | const service = getSubject(); 88 | service.setBundles([{ 89 | name: 'bundleA', 90 | urls: ['stuffA.js'], 91 | dependsOn: ['bundleB'], 92 | },{ 93 | name: 'bundleB', 94 | urls: ['stuffB.js'], 95 | }]); 96 | 97 | var assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('bundleA'))); 98 | assert.equal(assets.length, 2); 99 | assert.notEqual(assets.indexOf('bundleA'), -1); 100 | assert.notEqual(assets.indexOf('bundleB'), -1); 101 | }); 102 | 103 | function namesForBundles(bundles) { 104 | return Ember.A(bundles).mapBy('name'); 105 | } 106 | 107 | test('dependsOn can handle more complex dependency graphs', function(assert) { 108 | const service = getSubject(); 109 | service.setBundles([{ 110 | name: 'bundleA', 111 | urls: ['stuffA.js'], 112 | dependsOn: ['bundleB', 'bundleC'], 113 | },{ 114 | name: 'bundleB', 115 | urls: ['stuffB.js'], 116 | dependsOn: ['bundleD'], 117 | },{ 118 | name: 'bundleC', 119 | urls: ['stuffC.js'], 120 | dependsOn: ['bundleD'], 121 | },{ 122 | name: 'bundleD', 123 | urls: ['stuffD.js'], 124 | dependsOn: ['bundleE'], 125 | },{ 126 | name: 'bundleE', 127 | urls: ['stuffE.js'], 128 | }]); 129 | 130 | var assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('bundleA'))); 131 | assert.equal(assets.length, 5); 132 | assert.notEqual(assets.indexOf('bundleA'), -1); 133 | assert.notEqual(assets.indexOf('bundleB'), -1); 134 | assert.notEqual(assets.indexOf('bundleC'), -1); 135 | assert.notEqual(assets.indexOf('bundleD'), -1); 136 | assert.notEqual(assets.indexOf('bundleE'), -1); 137 | }); 138 | 139 | test('dependsOn doesnt break for circular dependencies', function(assert) { 140 | const service = getSubject(); 141 | service.setBundles([{ 142 | name: 'bundleA', 143 | urls: ['stuffA.js'], 144 | dependsOn: ['bundleB'], 145 | },{ 146 | name: 'bundleB', 147 | urls: ['stuffB.js'], 148 | dependsOn: ['bundleA'], 149 | }]); 150 | 151 | // from A.. 152 | var assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('bundleA'))); 153 | assert.equal(assets.length, 2); 154 | assert.notEqual(assets.indexOf('bundleA'), -1); 155 | assert.notEqual(assets.indexOf('bundleB'), -1); 156 | 157 | // from B.. 158 | var assets2 = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('bundleB'))); 159 | assert.equal(assets2.length, 2); 160 | assert.notEqual(assets2.indexOf('bundleA'), -1); 161 | assert.notEqual(assets2.indexOf('bundleB'), -1); 162 | }); 163 | 164 | test('namesForBundles returns the bundles based on the load order specified by the dependencies', function(assert) { 165 | const service = getSubject(); 166 | service.setBundles([{ 167 | name: '1', 168 | dependsOn: ['2'], 169 | }, { 170 | name: '2', 171 | dependsOn: ['4', '3'], 172 | }, { 173 | name: '3', 174 | dependsOn: ['4'], 175 | }, { 176 | name: '4' 177 | }]); 178 | 179 | var assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('1'))); 180 | assert.equal(assets.length, 4); 181 | assert.deepEqual(assets, ['4', '3', '2', '1']); 182 | 183 | service.setBundles([{ 184 | name: '1', 185 | dependsOn: ['2'], 186 | }, { 187 | name: '2', 188 | dependsOn: ['3', '4'], 189 | }, { 190 | name: '3', 191 | dependsOn: ['4'], 192 | }, { 193 | name: '4' 194 | }]); 195 | assets = namesForBundles(service.getDependentBundlesForBundle(service.getBundleByName('1'))); 196 | assert.equal(assets.length, 4); 197 | // 3 depends on 4, so even if 2 lists 3,4, the order is 4,3 198 | assert.deepEqual(assets, ['4', '3', '2', '1']); 199 | }); 200 | -------------------------------------------------------------------------------- /tests/dummy/app/app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Resolver from './resolver'; 3 | import loadInitializers from 'ember-load-initializers'; 4 | import config from './config/environment'; 5 | 6 | let App; 7 | 8 | Ember.MODEL_FACTORY_INJECTIONS = true; 9 | 10 | App = Ember.Application.extend({ 11 | modulePrefix: config.modulePrefix, 12 | podModulePrefix: config.podModulePrefix, 13 | Resolver 14 | }); 15 | 16 | loadInitializers(App, config.modulePrefix); 17 | 18 | export default App; 19 | -------------------------------------------------------------------------------- /tests/dummy/app/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/components/loading-for-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import layout from '../templates/components/loading-for-test'; 3 | 4 | export const StateForTest = { hasRendered: false }; 5 | export default Ember.Component.extend({ 6 | layout, 7 | didInsertElement () { 8 | // Not an easy way to prove that something render 9 | // since checking for a class on run.later 10 | // actually delays the render :( 11 | StateForTest.hasRendered = true; 12 | } 13 | }); 14 | -------------------------------------------------------------------------------- /tests/dummy/app/components/my-component.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import layout from '../templates/components/my-component'; 3 | 4 | export default Ember.Component.extend({ 5 | layout 6 | }); 7 | -------------------------------------------------------------------------------- /tests/dummy/app/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | 12 | 13 | 14 | 15 | {{content-for "head-footer"}} 16 | 17 | 18 | {{content-for "body"}} 19 | 20 | 21 | 22 | 23 | {{content-for "body-footer"}} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tests/dummy/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from 'ember-cli-bundle-loader/resolver'; 2 | 3 | export default Resolver; 4 | -------------------------------------------------------------------------------- /tests/dummy/app/router.js: -------------------------------------------------------------------------------- 1 | import LazyRouter from 'ember-cli-bundle-loader/lazy-router'; 2 | import config from './config/environment'; 3 | 4 | const Router = LazyRouter.extend({ 5 | location: config.locationType 6 | }); 7 | 8 | Router.map(function() { 9 | this.route('boot'); 10 | this.route('package1', function () { 11 | this.route('nested', {path: 'nested/:id'}); 12 | }); 13 | this.route('package2'); 14 | this.route('link-source'); 15 | this.route('link-target'); 16 | this.route('slow'); 17 | this.route('with-dependency'); 18 | }); 19 | 20 | export default Router; 21 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/routes/application.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | actions: { 5 | manualTransition() { 6 | this.get('router')._doTransition('package1', [], []); 7 | } 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/boot.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | export default Ember.Route.extend({ 3 | }); 4 | -------------------------------------------------------------------------------- /tests/dummy/app/routes/package1/nested.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | debug: 'from-package1', 5 | model: function () { 6 | return new Ember.RSVP.Promise(function (resolve) { 7 | Ember.run.later(()=>resolve({modelProperty: 42}), 1000); 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /tests/dummy/app/styles/app.scss: -------------------------------------------------------------------------------- 1 | .boot { 2 | background: red; 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/application.hbs: -------------------------------------------------------------------------------- 1 |

Welcome to Ember - with packaging and lazy loading

2 | 13 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/boot.hbs: -------------------------------------------------------------------------------- 1 |
2 | Boot 3 |
-------------------------------------------------------------------------------- /tests/dummy/app/templates/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/app/templates/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/app/templates/components/loading-for-test.hbs: -------------------------------------------------------------------------------- 1 |
LOADING....
-------------------------------------------------------------------------------- /tests/dummy/app/templates/components/my-component.hbs: -------------------------------------------------------------------------------- 1 | {{yield}} 2 | -------------------------------------------------------------------------------- /tests/dummy/app/templates/loading.hbs: -------------------------------------------------------------------------------- 1 | {{loading-for-test}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/package1.hbs: -------------------------------------------------------------------------------- 1 |
2 | Test 1 - this should never be used since the package1 template will take precedence 3 |
4 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/app/templates/package1/nested.hbs: -------------------------------------------------------------------------------- 1 | Nested - this should never be used since the package1 template will take precedence 2 | -------------------------------------------------------------------------------- /tests/dummy/config/bundles.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | module.exports = [{ 3 | name: 'package1', 4 | // [WIP] 5 | // This will be used later to concat packages into a single bundle. Right now there 6 | // is a one-one mapping in config, but when we lazy-load we think of bundles not packages 7 | packages: ['package1'], 8 | // Optional url, if not specified we will use ember's defaults. 9 | // this names will be used for fingerprinting, so for prod builds, if AssetRev finds it, 10 | // it will be fingerprinted and the URL field updated 11 | urls: ['assets/package1.js','assets/package1.css'], 12 | routeNames: ['^package1'], 13 | }, { 14 | name: ['with-dependency'], 15 | dependsOn: ['dependent'] 16 | }, { 17 | name: 'package-with-wrong-urls', 18 | urls: ['dosntexist.js'] 19 | } 20 | // The defaults are inferred by the packages (one to one, default URLs and top level route) 21 | // , { 22 | // name: 'package2', 23 | // packages: ['package2'], 24 | // urls: ['assets/package2.js','assets/package2.css'], 25 | // routeNames: [^package2] 26 | // } 27 | ]; 28 | -------------------------------------------------------------------------------- /tests/dummy/config/environment.js: -------------------------------------------------------------------------------- 1 | /* jshint node: true */ 2 | module.exports = function(environment) { 3 | var ENV = { 4 | modulePrefix: 'dummy', 5 | environment: environment, 6 | baseURL: '/', 7 | // NOTE: locationType hash is required for links between addons to work correctly 8 | locationType: 'hash', 9 | EmberENV: { 10 | FEATURES: { 11 | // Here you can enable experimental features on an ember canary build 12 | // e.g. 'with-controller': true 13 | } 14 | }, 15 | exportApplicationGlobal: true, 16 | APP: { 17 | // Here you can pass flags/options to your application instance 18 | // when it is created 19 | } 20 | }; 21 | 22 | if (environment === 'development') { 23 | // ENV.APP.LOG_RESOLVER = true; 24 | // ENV.APP.LOG_ACTIVE_GENERATION = true; 25 | // ENV.APP.LOG_TRANSITIONS = true; 26 | // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; 27 | // ENV.APP.LOG_VIEW_LOOKUPS = true; 28 | } 29 | 30 | if (environment === 'test') { 31 | // Testem prefers this... 32 | ENV.baseURL = '/'; 33 | ENV.locationType = 'none'; 34 | 35 | // keep test console output quieter 36 | ENV.APP.LOG_ACTIVE_GENERATION = false; 37 | ENV.APP.LOG_VIEW_LOOKUPS = false; 38 | 39 | ENV.APP.rootElement = '#ember-testing'; 40 | } 41 | 42 | if (environment === 'production') { 43 | 44 | } 45 | 46 | return ENV; 47 | }; 48 | -------------------------------------------------------------------------------- /tests/dummy/config/package-names.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | var fs = require('fs'), 3 | path = require('path'); 4 | 5 | function getDirectories(srcpath) { 6 | return fs.readdirSync(srcpath).filter(function (file) { 7 | return fs.statSync(path.join(srcpath, file)).isDirectory(); 8 | }); 9 | } 10 | 11 | // TODO: make it configurable, for now it's at the same level of app in the root. 12 | var packagesDir = path.join(__dirname, '..', 'packages'); 13 | module.exports = getDirectories(packagesDir); 14 | -------------------------------------------------------------------------------- /tests/dummy/packages/dependent/routes/dependent.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/packages/dependent/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/dependent/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/dependent/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/link-source/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/link-source/templates/link-source.hbs: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /tests/dummy/packages/link-target/controllers/link-target.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Controller.extend({ 4 | queryParams: ['sort', 'page'], 5 | sort: 'ASC', 6 | page: 1 7 | }); 8 | -------------------------------------------------------------------------------- /tests/dummy/packages/link-target/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/link-target/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/link-target/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/link-target/templates/link-target.hbs: -------------------------------------------------------------------------------- 1 | Page: {{page}}
2 | Sort: {{sort}}
-------------------------------------------------------------------------------- /tests/dummy/packages/load-assets-test/routes/load-assets-test.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/packages/load-assets-test/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/load-assets-test/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/load-assets-test/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/resolvers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/resolvers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/routes/package1.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | debug: 'from-package1', 5 | model: function () { 6 | return {modelProperty: 42}; 7 | } 8 | }); 9 | -------------------------------------------------------------------------------- /tests/dummy/packages/package1/styles/app.scss: -------------------------------------------------------------------------------- 1 | .package1 { 2 | background: green; 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/packages/package1/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package1/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package1/templates/package1.hbs: -------------------------------------------------------------------------------- 1 |
2 | Package 1 3 | {{model.modelProperty}} 4 |
5 | {{outlet}} -------------------------------------------------------------------------------- /tests/dummy/packages/package1/templates/package1/nested.hbs: -------------------------------------------------------------------------------- 1 | From the correct nested template -------------------------------------------------------------------------------- /tests/dummy/packages/package2/components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/components/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/controllers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/controllers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/helpers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/helpers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/models/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/resolvers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/resolvers/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/routes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/routes/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/routes/package2.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | debug: 'from-package2' 5 | }); 6 | -------------------------------------------------------------------------------- /tests/dummy/packages/package2/styles/app.scss: -------------------------------------------------------------------------------- 1 | .package2 { 2 | background: black; 3 | } 4 | -------------------------------------------------------------------------------- /tests/dummy/packages/package2/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/package2/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/packages/package2/templates/package2.hbs: -------------------------------------------------------------------------------- 1 |
2 | Package 2 3 |
4 | -------------------------------------------------------------------------------- /tests/dummy/packages/slow/routes/slow.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend({ 4 | debug: 'from-package1', 5 | model: function () { 6 | return new Ember.RSVP.Promise(function (resolve) { 7 | Ember.run.later(()=>resolve({modelProperty: 42}), 1000); 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /tests/dummy/packages/slow/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/slow/templates/slow.hbs: -------------------------------------------------------------------------------- 1 |
This took 1 second to render. Before that we showed the route's loading template
-------------------------------------------------------------------------------- /tests/dummy/packages/with-dependency/routes/with-dependency.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default Ember.Route.extend(); 4 | -------------------------------------------------------------------------------- /tests/dummy/packages/with-dependency/styles/app.scss: -------------------------------------------------------------------------------- 1 | // This styles are loaded only with this package 2 | -------------------------------------------------------------------------------- /tests/dummy/packages/with-dependency/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/packages/with-dependency/templates/.gitkeep -------------------------------------------------------------------------------- /tests/dummy/public/assets/load-assets-test2.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/public/assets/load-assets-test2.css -------------------------------------------------------------------------------- /tests/dummy/public/assets/load-assets-test2.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/dummy/public/assets/load-assets-test2.js -------------------------------------------------------------------------------- /tests/dummy/public/crossdomain.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /tests/dummy/public/robots.txt: -------------------------------------------------------------------------------- 1 | # http://www.robotstxt.org 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /tests/helpers/destroy-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | 3 | export default function destroyApp(application) { 4 | Ember.run(application, 'destroy'); 5 | } 6 | -------------------------------------------------------------------------------- /tests/helpers/module-for-acceptance.js: -------------------------------------------------------------------------------- 1 | import { module } from 'qunit'; 2 | import startApp from '../helpers/start-app'; 3 | import destroyApp from '../helpers/destroy-app'; 4 | 5 | export default function(name, options = {}) { 6 | module(name, { 7 | beforeEach() { 8 | this.application = startApp(); 9 | 10 | if (options.beforeEach) { 11 | options.beforeEach.apply(this, arguments); 12 | } 13 | }, 14 | 15 | afterEach() { 16 | if (options.afterEach) { 17 | options.afterEach.apply(this, arguments); 18 | } 19 | 20 | destroyApp(this.application); 21 | } 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /tests/helpers/resolver.js: -------------------------------------------------------------------------------- 1 | import Resolver from '../../resolver'; 2 | import config from '../../config/environment'; 3 | 4 | const resolver = Resolver.create(); 5 | 6 | resolver.namespace = { 7 | modulePrefix: config.modulePrefix, 8 | podModulePrefix: config.podModulePrefix 9 | }; 10 | 11 | export default resolver; 12 | -------------------------------------------------------------------------------- /tests/helpers/skip-if-phantom.js: -------------------------------------------------------------------------------- 1 | import { test, skip } from 'qunit'; 2 | 3 | var isPhantom = !!window._phantom; 4 | export default isPhantom ? skip : test; 5 | -------------------------------------------------------------------------------- /tests/helpers/start-app.js: -------------------------------------------------------------------------------- 1 | import Ember from 'ember'; 2 | import Application from '../../app'; 3 | import config from '../../config/environment'; 4 | 5 | export default function startApp(attrs) { 6 | let application; 7 | 8 | let attributes = Ember.merge({}, config.APP); 9 | attributes = Ember.merge(attributes, attrs); // use defaults, but you can override; 10 | 11 | Ember.run(() => { 12 | application = Application.create(attributes); 13 | application.setupForTesting(); 14 | application.injectTestHelpers(); 15 | }); 16 | 17 | return application; 18 | } 19 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Dummy Tests 7 | 8 | 9 | 10 | {{content-for "head"}} 11 | {{content-for "test-head"}} 12 | 13 | 14 | 15 | 16 | 17 | {{content-for "head-footer"}} 18 | {{content-for "test-head-footer"}} 19 | 20 | 21 | {{content-for "body"}} 22 | {{content-for "test-body"}} 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {{content-for "body-footer"}} 32 | {{content-for "test-body-footer"}} 33 | 34 | 35 | -------------------------------------------------------------------------------- /tests/integration/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/integration/.gitkeep -------------------------------------------------------------------------------- /tests/integration/components/my-component-test.js: -------------------------------------------------------------------------------- 1 | import { moduleForComponent, test } from 'ember-qunit'; 2 | import hbs from 'htmlbars-inline-precompile'; 3 | 4 | moduleForComponent('my-component', 'Integration | Component | my component', { 5 | integration: true 6 | }); 7 | 8 | // This default test makes sure that the inline-precompile plugin for HBS 9 | // works with bundle-loader see issues#3 10 | test('it renders', function(assert) { 11 | // Set any properties with this.set('myProperty', 'value'); 12 | // Handle any actions with this.on('myAction', function(val) { ... }); 13 | 14 | this.render(hbs`{{my-component}}`); 15 | 16 | assert.equal(this.$().text().trim(), ''); 17 | 18 | // Template block usage: 19 | this.render(hbs` 20 | {{#my-component}} 21 | template block text 22 | {{/my-component}} 23 | `); 24 | 25 | assert.equal(this.$().text().trim(), 'template block text'); 26 | }); 27 | -------------------------------------------------------------------------------- /tests/test-helper.js: -------------------------------------------------------------------------------- 1 | import resolver from './helpers/resolver'; 2 | import { 3 | setResolver 4 | } from 'ember-qunit'; 5 | 6 | setResolver(resolver); 7 | -------------------------------------------------------------------------------- /tests/unit/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/tests/unit/.gitkeep -------------------------------------------------------------------------------- /tests/unit/utils/load-assets-test.js: -------------------------------------------------------------------------------- 1 | import loadAssets, { singleInflightPromise } from 'ember-cli-bundle-loader/utils/load-assets'; 2 | import { module, test } from 'qunit'; 3 | import sinonTest from 'ember-sinon-qunit/test-support/test'; 4 | import wait from 'ember-test-helpers/wait'; 5 | import Ember from 'ember'; 6 | import ResourceHelper from 'ember-cli-bundle-loader/utils/-resource-helper'; 7 | 8 | module('Unit | Utility | load assets'); 9 | 10 | test('singleInflightPromise returns the same promise on subsequent calls until the first one is settled', function(assert) { 11 | assert.expect(3); 12 | 13 | let resolve; 14 | const promise = new Ember.RSVP.Promise(r=>resolve =r); 15 | let returnedPromise = singleInflightPromise('test-key', ()=>promise); 16 | assert.strictEqual(promise, returnedPromise); 17 | 18 | returnedPromise = singleInflightPromise('test-key', ()=>new Ember.RSVP.Promise(()=>{})); 19 | assert.strictEqual(promise, returnedPromise); 20 | 21 | resolve(); // Settling the promise should result in a different promise being returned 22 | return wait().then(() => { 23 | returnedPromise = singleInflightPromise('test-key', ()=>new Ember.RSVP.Promise(()=>{})); 24 | assert.notStrictEqual(promise, returnedPromise); 25 | }); 26 | }); 27 | 28 | test('load assets only requests one asset load for in-flight promises', function (assert) { 29 | assert.equal(0, $('script[src="assets/load-assets-test.js"]').length); 30 | assert.equal(0, $('link[href="assets/load-assets-test.css"]').length); 31 | loadAssets(['assets/load-assets-test.js', 'assets/load-assets-test.css']); 32 | loadAssets(['assets/load-assets-test.js', 'assets/load-assets-test.css']); 33 | loadAssets(['assets/load-assets-test.js', 'assets/load-assets-test.css']); 34 | return loadAssets(['assets/load-assets-test.js', 'assets/load-assets-test.css']).finally(function() { 35 | assert.equal(1, $('script[src="assets/load-assets-test.js"]').length); 36 | assert.equal(1, $('link[href="assets/load-assets-test.css"]').length); 37 | }); 38 | }); 39 | 40 | test('loadAssets throws if the urls dont have any of the valid extensions', function(assert) { 41 | return loadAssets(['invalidextensions.exe']).then(function() { 42 | assert.ok(false, 'promise should not be fulfilled'); 43 | }).catch(function (error) { 44 | assert.ok(error.match(/The specified url /)); 45 | }); 46 | }); 47 | 48 | sinonTest('loadAssets wont load an already loaded script', function (assert) { 49 | this.stub(ResourceHelper, 'isJavascriptLoaded').returns(true); 50 | var loaderSpy = this.spy(ResourceHelper, 'loadJavascript'); 51 | 52 | loadAssets(['assets/doesntmatter.js']); 53 | 54 | assert.notOk(loaderSpy.called); 55 | }); 56 | 57 | sinonTest('loadAssets wont load an already loaded stylesheet', function (assert) { 58 | this.stub(ResourceHelper, 'isStylesheetLoaded').returns(true); 59 | var loaderSpy = this.spy(ResourceHelper, 'loadStylesheet'); 60 | 61 | loadAssets(['assets/doesntmatter.css']); 62 | 63 | assert.notOk(loaderSpy.called); 64 | }); 65 | 66 | sinonTest('loadAssets calls the loader for javascript', function (assert) { 67 | this.stub(ResourceHelper, 'isJavascriptLoaded').returns(false); 68 | var loaderStub = this.stub(ResourceHelper, 'loadJavascript').returns(Ember.RSVP.resolve()); 69 | 70 | loadAssets(['assets/doesntmatter.js']); 71 | 72 | assert.ok(loaderStub.called); 73 | }); 74 | 75 | sinonTest('loadAssets calls the loader for stylesheets', function (assert) { 76 | this.stub(ResourceHelper, 'isStylesheetLoaded').returns(false); 77 | var loaderStub = this.stub(ResourceHelper, 'loadStylesheet').returns(Ember.RSVP.resolve()); 78 | 79 | loadAssets(['assets/doesntmatter.css']); 80 | 81 | assert.ok(loaderStub.called); 82 | }); 83 | -------------------------------------------------------------------------------- /tests/unit/utils/resource-helper-test.js: -------------------------------------------------------------------------------- 1 | import { module, test } from 'qunit'; 2 | import ResourceHelper from 'ember-cli-bundle-loader/utils/-resource-helper'; 3 | 4 | module('Unit | Utility | resource loader'); 5 | 6 | test('loadJavascript adds the appropriate script tag to the DOM', function (assert) { 7 | assert.expect(2); 8 | let testAsset = 'assets/load-assets-test2.js'; 9 | 10 | assert.equal(false, ResourceHelper.isJavascriptLoaded(testAsset)); 11 | 12 | return ResourceHelper.loadJavascript(testAsset).then(function() { 13 | assert.equal(true, ResourceHelper.isJavascriptLoaded(testAsset)); 14 | }); 15 | }); 16 | 17 | test('loadJavascript. The resource will not be considered as loaded if it failed', function (assert) { 18 | let testAsset = 'assets/dosntexist.js'; 19 | 20 | return ResourceHelper.loadJavascript(testAsset).catch(function() { 21 | assert.equal(false, ResourceHelper.isJavascriptLoaded(testAsset)); 22 | }); 23 | }); 24 | 25 | test('loadJavascript. The promise will fail if the resource cant be loaded', function (assert) { 26 | let testAsset = 'assets/dosntexist.js'; 27 | 28 | return ResourceHelper.loadJavascript(testAsset).then(()=> 29 | assert.notOk('The promise resolved when it was expected to fail') 30 | ).catch(() => 31 | assert.ok('The promise failed') 32 | ); 33 | }); 34 | 35 | test('loadStylesheet adds the appropriate stylesheet link to the DOM', function (assert) { 36 | assert.expect(2); 37 | let testAsset = 'assets/load-assets-test2.css'; 38 | 39 | assert.equal(false, ResourceHelper.isStylesheetLoaded(testAsset)); 40 | 41 | return ResourceHelper.loadStylesheet(testAsset).then(function() { 42 | assert.equal(true, ResourceHelper.isStylesheetLoaded(testAsset)); 43 | }); 44 | }); 45 | 46 | test('loadStylesheet. The promise will fail if the resource cant be loaded', function (assert) { 47 | let testAsset = 'assets/dosntexist.js'; 48 | 49 | return ResourceHelper.loadStylesheet(testAsset).then(()=> 50 | assert.notOk('The promise resolved when it was expected to fail') 51 | ).catch(() => 52 | assert.ok('The promise failed') 53 | ); 54 | }); 55 | 56 | 57 | test('loadStylesheet. The resource will not be considered as loaded if it failed', function (assert) { 58 | let testAsset = 'assets/dosntexist.css'; 59 | 60 | return ResourceHelper.loadStylesheet(testAsset).catch(function() { 61 | assert.equal(false, ResourceHelper.isStylesheetLoaded(testAsset)); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /vendor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MiguelMadero/ember-cli-bundle-loader/9c61a8fb9d7ffd1c797568773cd46e7a0c412768/vendor/.gitkeep --------------------------------------------------------------------------------