ember-engines / ember-asset-loader Goto Github PK
View Code? Open in Web Editor NEWAsset loading support for Ember applications
License: MIT License
Asset loading support for Ember applications
License: MIT License
Its not possible to add SRI since engine assets are loaded dynamically based on the meta config. Need an option on meta config to accept integrity, crossorigin attributes.
Hi, we have a use case where in order to prevent assets from being loaded too early and negatively impacting the page load time of a route, we would like to add an assert to ensure only the expected list of assets have been loaded at a particular lifecycle hook of a route. So if a new asset is added to be eagerly loaded, the assert would also need to be updated. Any thoughts? Thanks
fyi @sangm @chriskrycho
I wrongly assumed that Ember-CLI's storeConfigInMeta
option would also apply to the config/asset-manifest
meta tag.
Do you think that opting out of the meta tag is a realistic option?
I have an app already built that demonstrates this error. Please see this repo. In a nutshell, a fatal error is thrown when visiting an engine's route if that engine lists an external addon, which lists ember-asset-loader as a dependency, as a dependency.
Structure
Host app:
External addon ("some-addon"):
Error thrown:
The below error is thrown when visiting the engine's route
rsvp.js:26 Uncaught Error: Failed to load asset manifest. For browser environments, verify the meta tag with name "basic-engine/config/asset-manifest" is present. For non-browser environments, verify that you included the node-asset-manifest module. at Module.callback (asset-manifest.js:23) at Module.exports (loader.js:106) at Module._reify (loader.js:143) at Module.reify (loader.js:130) at Module.exports (loader.js:104) at requireModule (loader.js:27) at r (loader.js:176) at resolveInitializer (index.js:10) at registerInstanceInitializers (index.js:33) at loadInitializers (index.js:69)
After beginning to use ember-asset-loader, making a change to a css file in development caused live-reload to reload the entire page instead of just the css. I tracked this back to lib/asset-manifest-inserter.js: (https://github.com/ember-engines/ember-asset-loader/blob/master/lib/asset-manifest-inserter.js#L56-L58)
It appears from the code that there is intent to cache here, but perhaps it is not working?
I am running into an issue on firefox + lazy ember-engines.
Browsers fire the onload
event for link elements after the file is downloaded and parsed but BEFORE the css is applied to the document. mdn docs
I believe the css loader should be updated with a RAF or something similar to ensure the browser has painted BEFORE allowing the engine to render.
On chrome, this is no big deal, on firefox, I can actually see the content from my async engine render (incorrectly) before css is applied and everything snaps into place.
My unacceptable workaround:
// beforeModel hook of the async engines application route
beforeModel() {
if (browserIsFirefox) {
return new RSVP.Promise((resolve) => {
document.body.getBoundingClientRect(); // force a reflow
getRequestAnimationFrame(resolve); // ensure there is at least 1 paint before moving forward
});
}
return true;
}
I am about to launch a new feature on TheDyrt where you can repro this 100% of the time.
Writing down tasks from our discussion at the contributors workshop:
yarn install
and yarn install --no-lockfile
.I'm not 100% sure if this belongs here, but I think so.
I'm using lazyLoading engines.
In one of the engines, I have the following image:
<img src="assets/images/test.png">
When building, I use fingerprinting and a CDN with the following configuration:
// host-app's ember-cli-build.js
// ...
var cdnPrepend = false;
if (env === 'staging') {
cdnPrepend = 'https://XXX.cloudfront.net/';
}
if (env === 'production') {
cdnPrepend = 'https://YYY.cloudfront.net/';
}
var app = new EmberApp(defaults, {
fingerprint: {
enabled: isProductionLikeBuild,
prepend: cdnPrepend,
extensions: ['js', 'css', 'png', 'jpg', 'gif', 'map', 'svg']
},
assetLoader: {
generateURI: function(filePath) {
if (cdnPrepend) {
// Prevent duplicate slashes
return cdnPrepend.substr(0, cdnPrepend.length - 1) + filePath;
}
return filePath;
}
}
});
I get the image
<img src="https://XXX.cloudfront.net/assets/engines-dist/my-engine-name/assets/images/test-FINGERPRINT.png">
So basically, it is weirdly duplication the assets
portion to before the engines-dist
, which makes this fail. I'm not quite sure where/how this comes from.
Also, not sure if this is related, but the url is also wrongly rewritten if I use /assets/xxx
. Leaving the leading slash doesn't work in development for me, but in production it lead to /https://XXX.cloudfront.net/assets/engines-dist/my-engine-name/assets/images/test-FINGERPRINT.png
, which of course also doesn't work.
If I set lazyLoading: false
, it works as expected.
I'm using:
[email protected]
[email protected]
[email protected]
We cannot simply rely on file name lexicographic ordering from broccoli-funnel for generating the asset manifest.
Since ember-asset-loader
respects the ordering in terms of insertion order (which matters) we need to provide a way to configure file order.
It would be great if we support to load non-engine assets like any third party js or CSS (without needed to mention in index.html meta) lazily.
A template helper like this would allow folks to use lazy routeless engines with a nice(ish) syntax:
Example implementation (thanks to @mike183):
import Ember from 'ember';
const { Helper, inject, getOwner } = Ember;
export default Helper.extend({
assetLoader: inject.service("asset-loader"),
compute: function([ engineName ]) {
// Return engineName if engine is loaded
if (this._engineName !== undefined && this._engineName === engineName) {
this._engineName = engineName;
return this._engineName;
}
// need to expose the ability to introspect a bundle's state (loaded, unloaded, etc)
if (this.get('assetLoader').isLoaded(engineName)) {
this._engineName = engineName;
return this._engineName;
}
// Load unloaded engine
this.get("assetLoader").loadBundle(engineName).then(() => {
// Update this._engineName
this._engineName = engineName;
// Trigger recompution of helper
this.recompute();
});
// Returning null ensures nothing is rendered
return null;
}
});
I didn't notice this issue until after production.
It seems to be handled well by most browsers, but we have some users still on FF 48, which seems to sometimes crash when page loading inside a routable engine. However, this is ultimately irrelevant.
Our production app is https://www.typingtournament.com/
If you inspect the dom, you'll see the engine assets in <head>
use back slashes instead of forward slashes.
I develop on Windows, so I assume that is the issue because I haven't seen anyone else report this before.
I added a console.log like this in my ember-cli-build.js file:
let app = new EmberApp(defaults, {
...
assetLoader: {
generateURI: function(filePath){
console.log(filePath);
return filePath;
}
},
...
});
and my build log showed this:
d:\src\edalive\typingtournament\client\src>ember build
\ Building\engines-dist\tt-app\assets\engine-vendor.js
\engines-dist\tt-app\assets\engine.js
\engines-dist\tt-teacher\assets\engine-vendor.css
\engines-dist\tt-teacher\assets\engine-vendor.js
\engines-dist\tt-teacher\assets\engine.css
\engines-dist\tt-teacher\assets\engine.js
\engines-dist\tt-web\assets\engine-vendor.css
\engines-dist\tt-web\assets\engine-vendor.js
\engines-dist\tt-web\assets\engine.css
\engines-dist\tt-web\assets\engine.js
cleaning up...
Built project successfully. Stored in "dist/".
I'll fix this with js string manipulation in the generateURI method for now, but this should probably also be handled better.
After run yarn run test:sauce
Last login: Sun May 10 19:56:15 on ttys001
➜ ember-asset-loader git:(master) yarn run test:sauce
yarn run v1.22.4
$ ember test --config-file testem.sauce.js --test-port 7000
WARNING: Node v12.13.0 is not tested against Ember CLI on your platform. We recommend that you use the most-recent "Active LTS" version of Node.js. See https://git.io/v7S5n for details.
Could not start watchman
Visit https://ember-cli.com/user-guide/#watchman for more info.
DEPRECATION: Ember will stop including jQuery by default in an upcoming version. If you wish keep using jQuery in your application explicitly add `@ember/jquery` to your package.json
Environment: test
Warning: ignoring input sourcemap for vendor/ember/ember.debug.js because ENOENT: no such file or directory, open '/var/folders/0v/jpdg1flj3qscvbvt728pgt8c0000gn/T/broccoli-9719scuSj4FGFmkw/out-123-broccoli_debug_debug_7_vendor_js/vendor/ember/ember.debug.map'
Warning: ignoring input sourcemap for vendor/ember/ember-testing.js because ENOENT: no such file or directory, open '/var/folders/0v/jpdg1flj3qscvbvt728pgt8c0000gn/T/broccoli-9719scuSj4FGFmkw/out-147-broccoli_debug_debug_10_test_support_js/vendor/ember/ember-testing.map'
cleaning up...
Built project successfully. Stored in "/Users/villander/Projects/ember-asset-loader/tmp/class-tests_dist-zfQE2hCj.tmp".
not ok 1 SL_CHROME - [undefined ms] - error
---
message: >
Error: Browser exited unexpectedly
Stderr:
Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)
at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)
at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11
Stdout:
Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
Log: |
{ type: 'error', text: 'Error: Browser exited unexpectedly' }
{
type: 'error',
text: 'Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n' +
' at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)\n' +
' at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)\n' +
' at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)\n' +
' at Module._compile (internal/modules/cjs/loader.js:956:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:812:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:724:14)\n' +
' at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)\n' +
' at internal/main/run_main_module.js:17:11\n'
}
{
type: 'log',
text: 'Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n'
}
...
not ok 2 SL_EDGE - [undefined ms] - error
---
message: >
Error: Browser exited unexpectedly
Stderr:
Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)
at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)
at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11
Stdout:
Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
Log: |
{ type: 'error', text: 'Error: Browser exited unexpectedly' }
{
type: 'error',
text: 'Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n' +
' at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)\n' +
' at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)\n' +
' at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)\n' +
' at Module._compile (internal/modules/cjs/loader.js:956:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:812:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:724:14)\n' +
' at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)\n' +
' at internal/main/run_main_module.js:17:11\n'
}
{
type: 'log',
text: 'Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n'
}
...
not ok 3 SL_IE10 - [undefined ms] - error
---
message: >
Error: Browser exited unexpectedly
Stderr:
Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)
at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)
at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11
Stdout:
Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
Log: |
{ type: 'error', text: 'Error: Browser exited unexpectedly' }
{
type: 'error',
text: 'Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n' +
' at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)\n' +
' at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)\n' +
' at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)\n' +
' at Module._compile (internal/modules/cjs/loader.js:956:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:812:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:724:14)\n' +
' at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)\n' +
' at internal/main/run_main_module.js:17:11\n'
}
{
type: 'log',
text: 'Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n'
}
...
not ok 4 SL_IE11 - [undefined ms] - error
---
message: >
Error: Browser exited unexpectedly
Stderr:
Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)
at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)
at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)
at Module._compile (internal/modules/cjs/loader.js:956:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)
at Module.load (internal/modules/cjs/loader.js:812:32)
at Function.Module._load (internal/modules/cjs/loader.js:724:14)
at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)
at internal/main/run_main_module.js:17:11
Stdout:
Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.
Log: |
{ type: 'error', text: 'Error: Browser exited unexpectedly' }
{
type: 'error',
text: 'Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n' +
' at launch (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/launch.js:21:28)\n' +
' at main (/Users/villander/Projects/ember-asset-loader/node_modules/saucie/lib/index.js:7:10)\n' +
' at Object.<anonymous> (/Users/villander/Projects/ember-asset-loader/node_modules/ember-cli-sauce/bin/cli.js:6:1)\n' +
' at Module._compile (internal/modules/cjs/loader.js:956:30)\n' +
' at Object.Module._extensions..js (internal/modules/cjs/loader.js:973:10)\n' +
' at Module.load (internal/modules/cjs/loader.js:812:32)\n' +
' at Function.Module._load (internal/modules/cjs/loader.js:724:14)\n' +
' at Function.Module.runMain (internal/modules/cjs/loader.js:1025:10)\n' +
' at internal/main/run_main_module.js:17:11\n'
}
{
type: 'log',
text: 'Bail out! Error: Please, provide the username and the access key for SauceLabs. Use the option --help for more information.\n'
}
...
1..4
# tests 4
# pass 0
# skip 0
# fail 4
Testem finished with non-zero exit code. Tests failed.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
➜ ember-asset-loader git:(master)
So, I have a engine with lazyLoading: false
inside a fresh ember app. My engine have addons and one of them have the code below:
# index.js
/* eslint-env node */
'use strict';
module.exports = {
name: 'ember-cli-neutral',
contentFor(type, config) {
if (type === 'head') {
if (config.googleFonts) {
let families = config.googleFonts.join('|');
return '<link href="https://fonts.googleapis.com/css?family=' + families + '" rel="stylesheet">'; // eslint-disable-line
}
}
}
};
# environment.js
/* eslint-env node */
'use strict';
module.exports = () => {
const ENV = {
googleFonts: [
'Roboto:400,500'
]
};
return ENV;
};
If I run engine separately the link of google fonts works perfectly, but if I run inside the fresh ember app not.
Perhaps a feature for future or it's outside the scope of this project?
When running an Ember application in Node (such as through FastBoot), the asset-manifest
module blows up since it can't read from the DOM (which doesn't exist).
There are patterns to handle this, but it raises the overarching issue of how should lazy assets be handled within a non-browser environment.
Open questions:
My current thinking is:
In a Node process, all assets should be loaded upfront (need build targets in order to do this easily), but the manifest should still be present so that if a code path expects to load a bundle (or similar) it doesn't kill the app. This would mean that the loader functions should all return immediately resolving Promises (Promise.resolve()
).
@nathanhammond @dgeb @rwjblue would greatly appreciate hearing your thoughts on this
Tasks:
When an application has more than one ember addon installed that exports a ManifestGenerator
-extended addon, a meta tag is inserted into the head-footer
content-for block because each addon has a contentFor
hook defined by ManifestGenerator
:
For example, with two addons that use ManifestGenerator
, before post-processing, the index.html may look like:
<meta name="my-app/config/asset-manifest" content="%GENERATED_ASSET_MANIFEST%">
<meta name="my-app/config/asset-manifest" content="%GENERATED_ASSET_MANIFEST%">
After post-processing, the first meta tag is replaced by the contents of the asset manifests provided by both addons, so it has all of the correct content, but there is an extraneous meta tag that remains:
<meta name="my-app/config/asset-manifest" content="%7B%22bundles%22%3A%7B%22...">
<meta name="my-app/config/asset-manifest" content="%GENERATED_ASSET_MANIFEST%">
Ideally even if multiple addons consumed by the host app are using ManifestGenerator
, only a single asset-manifest meta tag would be inserted, or the extra ones be removed during the post-processing when the manifest is being injected.
It would be great if there was a way to make this less noisy:
If it runs in afterEach
after every test, that can really pollute a test run's output.
When working on a self contained engine it is quite possible to end up without any vendor'ed JS or CSS. In that scenario engine-vendor.css
and engine-vendor.js
are empty files.
I propose that empty files should be excluded from the generated asset-manifest.json
by default.
Any objections?
Attempting to inject an unknown injection: 'service:assetLoader'
is thrown when adding ember-engines
to project with existing unit tests for routes and components. Can be worked around by adding service:assetLoader
to the needs
array, however this is not ideal and adds unnecessary cognitive load to the addon user.
Hey,
I am having an issue with lazy engines + fastboot resulting in a FOUC.
So far, I have nailed it down to 2 issues,
I propose we teach each loader how to load itself in the browser and in node land.
In node land, it would just append a script/link tag to the dom.
Get error EISGIT when performing npm-install
Error message:
npm ERR! path ...p/node_modules/ember-asset-loader
npm ERR! code EISGIT
npm ERR! git .../node_modules/ember-asset-loader: Appears to be a git repo or submodule.
npm ERR! git .../node_modules/ember-asset-loader
npm ERR! git Refusing to remove it. Update manually,
npm ERR! git or move it out of the way first.
Assets are loaded absolutely instead of relative to account for a rootURL setting
After #11 I would like to make sure there are more tests added. The current ones should cover most of the generation needs but the extensibility API could use work.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.