Skip to content
This repository has been archived by the owner on Aug 2, 2018. It is now read-only.

duo-css: should parse each of the css files in "styles": [...] #36

Closed
matthewmueller opened this issue Jun 9, 2014 · 35 comments
Closed

Comments

@matthewmueller
Copy link
Contributor

I think this will allow us to continue to support components with JS and CSS. It's a little weird though, because there should probably only be one style that imports everything else.

@yields @ianstormtaylor @visionmedia could use some thoughts here.

@ianstormtaylor
Copy link
Contributor

Is this for backwards compat with Component or for regular Duo stuff? I can outline how I was hoping the CSS stuff would work if that's helpful

@matthewmueller
Copy link
Contributor Author

i have a good idea of how CSS will work within an app. Basically just point to a single css file and have that do all the importing so you get the smallest build necessary, but for components i'm not so sure.

yah, if you have some ideas, i'd appreciate it. trying to figure this stuff out now. backwards compat is necessary, but we can also do stuff that will only work in duo

@ianstormtaylor
Copy link
Contributor

What are the other distinctions that we have between "apps" and "components"? I think it's just that main is implied by the arg you pass to the CLI right now? Other than that it seems the same? Just curious so I can keep my understanding right.

What I imagined was that both cases would have a CSS entry point file, defaulting to index.css that would contain @import rules. For apps it would just be something like this I think...

$ duo index.css > build.css

...and then for packages, they would have a main.css key to define what the entry point is...

{
  "name": "toggle",
  "repository": "segmentio/toggle",
  "main": {
    "js": "lib/index.js",
    "css": "lib/index.css"
  }
}

...and the same rules would then apply.

Makes it easy, since to maintain backwards compat for existing components, we just need to generate an entry point file with imports to everything in styles...

fs.writeFileSync('index.css', styles.map(function(file){
  return '@import "' + file + '"';
}).join('\n'));

...and I think that should cover it?

@matthewmueller
Copy link
Contributor Author

yep, this works for me. then we'll check main to see if it's a string or an object and act accordingly.

@ianstormtaylor
Copy link
Contributor

Yup, and I even just realized we can nicely check the extension if it's a string for even more convenience for single-use packages:

{
  "main": "lib/index",     // { js: "lib/index.js" }
  "main": "lib/index.js",  // { js: "lib/index.js" }
  "main": "lib/index.css"  // { css: "lib/index.css" }
}

But that might have been obvious to everyone else already :)

@matthewmueller
Copy link
Contributor Author

ohh yah, <3

@matthewmueller
Copy link
Contributor Author

@ianstormtaylor I don't think this is going to work for components that depend on existing CSS dependencies.

I'm not sure how many of them there are, but in order for a component's CSS to depend on CSS from another component in duo, it would need something like:

component/tip:

@import "aurora-tip"

note: component/tip doesn't depend on aurora-tip, this is just for demonstration purposes

Which is definitely not backwards compatible with component. This is probably an edge-case, but I've noticed you've done a lot of CSS components, so I wanted to run this by you.

@matthewmueller
Copy link
Contributor Author

oh... the logo/logo is a good example. duo doesn't care about dependencies in the manifest, if there's no reference to them in the CSS. So logo/logo won't get picked up by logo/apple.

you think that's going to be a problem?

/cc @yields

@ianstormtaylor
Copy link
Contributor

Just running into this issue again. Was trying to use one of our existing components and its styles array wasn't getting picked up. Would be nice for backwards compat if we figure out a solution to this, otherwise we have to manually import each of the files itself with a bunch of :/path/to/file imports

@matthewmueller
Copy link
Contributor Author

Yah... this was a compromise that I'm hoping we can get away with. I think you guys are the biggest and perhaps the only pure CSS component (with deps) users.

The solution I'd like to propose is to update the CSS components to do:

// in index.css

@import "logo/logo";
@import "./some/other/file.css";

...


This has the added benefit of only including the CSS that you need instead of adding all the CSS files in the styles array.

I'm down to help with this transition but I know this ends up breaking component compatibility so let me know if this is not feasible and we can work around it.

Sent from my iPhone

On Aug 3, 2014, at 16:24, Ian Stormn Taylor notifications@github.com wrote:

Just running into this issue again. Was trying to use one of our existing components and its styles array wasn't getting picked up. Would be nice for backwards compat if we figure out a solution to this, otherwise we have to manually import each of the files itself with a bunch of :/path/to/file imports


Reply to this email directly or view it on GitHub.

@ianstormtaylor
Copy link
Contributor

Ah nice I like that interim fix with the index.css. Sounds good to me!

@matthewmueller
Copy link
Contributor Author

oh i thought that would be a permanent fix haha. what do you have in mind?

@ianstormtaylor
Copy link
Contributor

Ah oops I meant interim as in until we get rid of component altogether. Just liked that it was backwards compat still in the interim as we switch over

@matthewmueller
Copy link
Contributor Author

oh shoot, the rest of the message got cut off becuase i was messaging on my phone... dunno if you saw:

...


This has the added benefit of only including the CSS that you need instead of adding all the CSS files in the styles array.

I'm down to help with this transition but I know this ends up breaking component compatibility so let me know if this is not feasible and we can work around it.

Sent from my iPhone

@ianstormtaylor
Copy link
Contributor

Ah nice, yeah that's also cool. Been digging the total control over ordering of deps in css land compared to before. way more sensical :)

@matthewmueller
Copy link
Contributor Author

yep haha :-)

@lancejpollard
Copy link
Member

@ianstormtaylor @matthewmueller fyi this actually won't work because check it out:

logo/twitter-ads@6d505f4

That seemed like an easy fix. This way, component pulls from style.css, with all the dependencies coming from the styles field in component.json. Then, duo can pull from index.css with all the dependencies imported with @import.

However, this doesn't actually work as expected (maybe I just misinterpreted from the beginning).

Duo first checks component.json's styles[0] field, and then tries index.css. Which means it will always pull styles[0] if it's being ported from component. Which means we can't port it using duo's current handling of this (i.e. we can't support both component and duo at the same time).

It seems like it should work the other way around, if we're not going to be supporting CSS in the manifests (#252), yeah? Basically, duo should first check index.css, and then fall back to styles[0] if missing?

@matthewmueller
Copy link
Contributor Author

oh yah shoot, index.css would happen if it doesn't find anything in the component.json. Here's the culprit: https://github.com/duojs/duo/blob/master/lib/duo.js#L542

An easy fix would be:

{
  "main": "index.css",
  "styles": [
    "style.css"
  ]
}

or...

{
  "styles": [
    "index.css",
    "style.css"
  ]
}

I'm not sure I want to support this... it would require an exists('index.' + type) check. I think I'd rather have a proper manifest or no manifest at all.

@lancejpollard
Copy link
Member

@matthewmueller ok cool, the main: index.css should do it :) thanks

@lancejpollard
Copy link
Member

@matthewmueller gahh, nevermind it won't do it because we already have main: index.js in many of them. any other suggestions?

{
  "styles": [
    "index.css",
    "style.css"
  ]
}

that wouldn't work because in index.css you would have @import ./style and such, which would break component.

@matthewmueller
Copy link
Contributor Author

@lancejpollard duo adds support for:

{
  "main": {
    "css": "index.css",
    "js": "index.js"
  }
}

for multi-asset components.

@lancejpollard
Copy link
Member

@matthewmueller any reason why you don't want that extra exists('index.' + type) check? it would definitely solve the problem :D

does component support that?

"main": {
  "css": "index.css",
  "js": "index.js"
}

@matthewmueller
Copy link
Contributor Author

arg, we need more docs haha. ian simplified / improved the docs a lot, but we also lost a bunch of info. that was originally in the components section of the docs. going to add a "creating a duo component" section.

@ianstormtaylor
Copy link
Contributor

I think the main hacks won't solve the problem here because changing the main to anything other than a single .js file string will break for component?

It seems like there isn't a simple workaround for these, so maybe we should add support to Duo core to properly create an @import-ing file from the .styles array instead?

@matthewmueller
Copy link
Contributor Author

oh yah, good point. yah i don't think there's a great way to add support for both :-/

@lancejpollard
Copy link
Member

alright i guess for now we'll probably just fork duo and go from there. would you accept a pr or no you don't want to support this? basically it doesn't seem there is anyway we can both use duo and component at the same time while we refactor/port stuff over without this.

some other workarounds other than forking duo are:

  • creating new repos for every css component (which isn't really feasible)
  • going through all the current css components and locking their versions for component, and then going through all repos using those and tie them to those components (but that would take far too long, probably a few weeks, so it's not worth it)
  • write some script that does some tricks where, after duo downloads all components, it goes through and looks for index.css in each component, and then rewrites the component.json so it points to that now instead of style.css. this might work because for the current project we would be using duo, but it's also super hacky (and we'd have to do it this way until every old project was moved off of component)

@matthewmueller
Copy link
Contributor Author

Would the exists check fix it? Basically the order of preference would be:

  1. try to load from "index." + type
  2. try to load from manifest

I just wonder if it's a good idea to ignore the manifest if it's there. As I've mentioned a few times before, the logo components are the only public repos that I know of that would need to be updated.

The only components that need to get updated are the CSS components that have CSS dependencies. Do you guys have a lot of them?

@lancejpollard
Copy link
Member

@matthewmueller is there a way we can maybe make a plugin or something to hack around this?

@lancejpollard
Copy link
Member

@matthewmueller I guess what's partly confusing for me is why you're supporting the manifest for CSS at all? The way it works now it pretty much doesn't work for any of the components we have other than the simple ones that have index.css and no dependencies. We have many CSS components that have more than 1 file, and usually they're structured (for whatever reason) like this lib/index.css, lib/some-other.css, and styles[0] = lib/index.css. But we can't port these to duo, and at the same time support component.json, because we can't add @import statements to lib/index.css without it breaking component.

What I'm saying is, styles[0] is only there to support existing components, but it actually doesn't support the existing component way of doing it (which we're seeing in all these blockers I've been running into). So component should update everything to index.css, and in the meantime we can have a fallback to styles[0] for them, rather that making that first-class and index.css second class.

@matthewmueller
Copy link
Contributor Author

Okay, haha. Umm... yah actually you might be able to:

duo.use(function(file, entry) {
  if ('css' != file.type) return;
  if ('css' != entry.type) return

  var json = require(join(dirname(file.path), 'component.json'));
  if (!json.styles || !json.styles.length) return;

  for (var i = 0, style; style = json.styles[i++];) {
    file.src = "@import " + style + ";\n" + file.src;
  }
}); 

This is untested, haha. But that should get the point.

@matthewmueller
Copy link
Contributor Author

@lancejpollard the CSS manifest is for new components, not old ones. Duo has a much more powerful CSS component system now, as it will only include the stuff that you need, just like JS and it will also respect order:

index.css:

@import "normalize.css";
@import "grid";

// ...

component.json:

{
  "name": "css-component",
  "dependencies": {
    "necolas/normalize.css": "*",
    "some/grid": "*"
  }
}

Using the component:

@import "matthewmueller/css-component";

@matthewmueller
Copy link
Contributor Author

@lancejpollard try and get the plugin working, if you have any questions let me know. I can take a crack at it too. It will be important for the transition.

@lancejpollard
Copy link
Member

@matthewmueller for sure, that totally makes sense. That's how we've been doing it definitely.

But right now, here's the order of precedence. Here's an existing CSS component

{
  "main": "index.js",
  "styles": [
    "lib/index.css",
    "lib/form.css",
    "lib/form-legend.css",
    "lib/form-input.css"
  ],
  "dependencies": {
    "org/form": "*", // which requires normalize.css, perhaps
    "org/input": "*"
  }
}

Porting to duo you make it like this (same component.json, but just new index.css):

{
  "main": "index.js",
  "styles": [
    "lib/index.css",
    "lib/form.css",
    "lib/form-legend.css",
    "lib/form-input.css"
  ],
  "dependencies": {
    "org/form": "*", // which requires normalize.css, perhaps
    "org/input": "*"
  }
}
@import './lib/form';
@import './lib/form-legend';
@import './lib/form-input';
@import 'org/form';
@import 'org/input';

It should work like this imo:

  1. check index.css, if there then load that
  2. otherwise check styles[0]. but, that wouldn't even work for a component like that (which is another reason why styles[0] shouldn't be first. Really, it should do styles.map() type thing to support existing components.

Basically, duo isn't currently supporting existing components anyways, so might as well change the order of precedence.

@lancejpollard
Copy link
Member

kk will try the plugin method

@matthewmueller
Copy link
Contributor Author

ah yah, i think we can get that working. here's more docs on duo#use:

https://github.com/duojs/duo/blob/master/docs/api.md#duousefngen

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

No branches or pull requests

3 participants