Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add more declarative way of adding/removing assets for fastboot #413

Closed
scottmessinger opened this issue Jun 1, 2017 · 6 comments
Closed

Comments

@scottmessinger
Copy link

Problem:
The current guide to migrating fastboot is very helpful, but requires understanding far more about broccoli and the fastboot manifest than in the past. Because of the increased knowledge, updating an addon to be compatible with fastboot 1.0 is challenging. Ryan had an experience similar to mine:
image

Specifically, the migration paths that have proved the most challenging are importing in fastboot build and importing for a browser build. Look at the first two uses cases in the upgrading gist for more.

This problem also affects developers seeking to make their apps compatible for fastboot by including or excluding libs for fastboot.

Goals:
While having low level primitives is very useful for edge cases, creating a more declarative api for including an asset for browser or fastboot would make the migration easier and reduce the amount of knowledge addons authors have to learn. By lowering the barriers, new addons will be more likely to be fastboot compat out of the gate and existing addons will be more quickly migrated.

Ideally, a solution would:

  • require no new broccoli plugins like broccoli-stew
  • require no knowledge of the fastboot manifest
  • require no knowledge of the fastboot broccoli callback (updateFastBootManifest)

A possible solution:
I'm not knowledgable enough of ember-cli to know the best path forward, but as a novice, I'd love to see something like:

// If not specified, "importInFastBoot" would be `true`
// and all imported assets would be included in a fastboot build
app.import("filename.js", {importInFastBoot: false})
@scottmessinger
Copy link
Author

Related to #387

@stefanpenner
Copy link
Contributor

stefanpenner commented Jun 1, 2017

Ideally, a solution would:

require no new broccoli plugins like broccoli-stew
require no knowledge of the fastboot manifest
require no knowledge of the fastboot broccoli callback (updateFastBootManifest)

Often easy and simple aren't the same things so we may require additional knowledge here, likely a two pronged approach is appropriate:

  • see if common operations can shake out in simpler ways
  • improve documentation/knowledge required to use the above tools successfully

@kratiahuja
Copy link
Contributor

I'll take a stab at this over the weekend. I have an idea in my mind but want to spike out and think aloud.

@kratiahuja
Copy link
Contributor

kratiahuja commented Jun 5, 2017

@scottmessinger Thanks for the write up and your thoughts! Really appreciate it since it helps us improve things before releasing. Reading the original issue that you posted, I would like to call it out very clearly that there is NO two different builds/environments any longer. Assets aren't any longer forked for browser and fastboot that you can chose if a lib should be included or not included in fastboot/browser. That's the reason we are proposing to wrap libraries to be only run in browser with the FastBoot check.

Whichever assets are loaded in browser are loaded in fastboot too. You can additionally load overrides or additional library in fastboot. That's how the new build works.

I think the confusion is more around the assumption that fastboot is still running two builds when it is not. Also to that point, ember-cli is fastboot agnostic. It doesn't or shouldn't need to know anything about fastboot. FastBoot takes inspiration from ember-cli and builds its own API. It just builds the extra asset containing overrides that need to be loaded in fastboot.

When refactoring the build to make it performant and shippable as a 1.0 candidate, we tried hard to keep it backwards compatible, however this wasn't easy as it sounds.

To answer your original concern of the first two migration path, here is what I propose:

Case 1: Running a library only in browser environment

I created a utility in github called fastboot-transform which wraps the stew magic away. This should address your concern about "require no new broccoli plugins like broccoli-stew". In order to import a library that is only meant to run in browser you could do currently use fastboot-transform and not need to worry about stew.

 treeForVendor(tree) {
   // as addon author you already were doing this
   var browserLib = new Funnel(..);

   return new MergeTrees([tree, fastboot-transform(browserLib)]);
}

included(app) {
  app.import(path);

Improvement

A substantial improvement to the above scheme is proposed via the app.import in this PR which would basically mean you need to do the following:

treeForVendor(tree) {
  //everything remains same as you had pre rc builds. you don't need to even use fastboot-transform here
}

included(app) {
  app.import(path, {
     using: [{
         transformation: fastboot-transform
    }]);
}

This would work well for bower libraries and node_modules that are imported as well.

Case 2: Running a library only in fastboot

I disagree here that addon authors that wish to make their addons fastboot complaint should not have knowledge about fastboot. As addon authors if you want to make your addon compatible to be running in fastboot, you need to be aware of the public API fastboot is exposing.

updateFastBootManifest is a simple hook to add a library you want to load in fastboot only. It is not a low level API. The way app.import by default imports it in the vendor.js, updateFastBootManifest allows you to load your library after the vendor file in fastboot. It's pretty much identical in what they both do.

The simplest example of before and after the refactor is:
BEFORE:

 included(app) {
    if (process.env.EMBER_CLI_FASTBOOT) {
      app.import(fastbootLibPath);
   }
} 

AFTER:

included(app) {
   app.import(fastbootLibPath, { outputFile: 'assets/fastboot-lib.js' }
}

updateFastBootManifest(manifest) {
  // load my fastboot lib with other vendor files
  manifest.vendorFiles.push('assets/fastboot-lib.js');
  return manifest;
}

outputFile is a public API of ember-cli described here and updateFastBootManifest is a public API of fastboot described here.

If you think updateFastBootManifest is a bit wrongly named or verbose, we can come up with a wrapper API to be something like (though I would like to understand why is updateFastBootManifest causing so much friction and how we can improve it rather than creating a new wrapper):

var fastbootUtility = require('ember-cli-fastboot/fastboot-build-utility');

included(app) {
  fastboot.import(path);
}

Happy to review if someone wants to PR it.

Migration guide

While I totally agree the migration guide is not in its best state but @tsubomii is working on improving it. We can probably post some real world examples of addons that have already done the migration in order to help addon authors to migrate their addons. This would greatly reduce the friction for addon authors and would instill more confidence in the migration. Do you think that would help?

Any other ideas or help on improving the guide/docs or migration are greatly appreciated!

@scottmessinger
Copy link
Author

Thanks, @kratiahuja! A few response below:

I would like to call it out very clearly that there is NO two different builds/environments any longer

Agreed about the builds and the difference in the use of "environments" might just be semantics. With fastboot, I think of my app as having the same build (same concatenated javascript files) running in two environments: node & the browser.

When refactoring the build to make it performant and shippable as a 1.0 candidate, we tried hard to keep it backwards compatible, however this wasn't easy as it sounds.

Thanks again for all your hard work on this.

Case 1 improvement

included(app) {
  app.import(path, {
     using: [{
         transformation: fastboot-transform
    }]);
}

I think this looks great! My one suggestion was the name: "fastboot transform" makes me think it's a generic transform with some generic positive outcome and not "put a guard around this script so it doesn't run in node." Again, the name might be perfect as it's intended to be a generic transform. But, if the goal is specific, might I suggest a more pointed name. Perhaps, disable-in-fastboot or disable-in-node or ....naming is hard. fastboot-transform might be the best, but if it could be changed, I think it would be very helpful.

Case 2: Running only in fastboot

fastboot complaint should not have knowledge about fastboot.

I agree with you and I think I misspoke early. I think your point is exactly right, "you need to be aware of the public API." I went back and looked at the original gist and I think it was the combination of three callbacks treeForVendor, included, and updateFastBootManifest that
made it feel rather verbose and more than the public API. Moving to two callbacks (and skipping the mergeTrees and Funnel in treeForVendor) makes it much nicer, IMO.

In answer to your questions, "updateFastBootManifest is a bit wrongly named or verbose", I think its fine. The two steps of importing the file and then adding to the fastboot manifest seem reasonable.

Migration guide

Just to clarify, the gist was always great -- it correctly exposed the complexity of the migration and help facilitate the conversation about improving it!

I think the changes above address my concerns and I'm so grateful for the time & work you've put into this, @kratiahuja.

@kratiahuja
Copy link
Contributor

The new API to make easy for apps to import fastboot incompatible libraries is merged. For addon, I will provide an API in fastboot-transform and is being tracking here: kratiahuja/fastboot-transform#7.

Going to close this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants