openstyles / stylus

Stylus - Userstyles Manager
https://add0n.com/stylus.html
GNU General Public License v3.0
5.5k stars 306 forks source link

@import caching #465

Open silverwind opened 6 years ago

silverwind commented 6 years ago

CSS imports allow authors to include external stylsheets which are then cached in the browser according to HTTP caching rules. In the scope of a user style, I think in most cases, it would be more desirable to cache imported styles forever, or until the style is updated, for both performance and build reproducibilty. Greasemonkey's require already works like this:

Each @require is downloaded once, when the script is installed, and stored on the user's hard drive alongside the script.

The reason I'd like to see this is because I'd like to host a imported style on GitHub on a static raw URL but would not want users of old versions of my user style to download potentially incompatible updates to the imported style while they surf the site. I'd like to instead couple imports to the userstyle itself, but in the GitHub case, one can not control the caching headers sent on the HTTP response.

the-j0k3r commented 6 years ago

This is a copy and paste from my reply to you in GHD.

1) It would likely be a security issue to allow users to create styles that would potentially import unknown CSS especially usercss, Stylus doesnt have any checks bulit in to warn/block of these potential dangers at this time. openstyles/stylus#385 or other malicious payloads.

2) its cached, probably no user accessible like the style data and not in a easily readable format. If it requires users to go dig in hard drive to find this cached data, its already alarm bell in my head.

3) I dont like not knowing what am adding to my browser under any circumstances,

4) I wouldn't use anything that requires this type of that in greasemonkey either.

You're welcome to do it, but I would never use it on principle because I think bad actors already have enough vectors to attack computers, they dont need any more ideas, In a different world maybe, not this one :) I read security news every day with my cup of coffee, so no thanks..

Having said that, I realize not everyone has malicious intents but it would make me feel a lot better as a user to know Stylus would not allow any malicious stuff to be imported or cached, but then this is an uphill struggle because bad actors find more clever ways to bypass measures Stylus would take to prevent this.

Too much work for little gain IMO.

eight04 commented 6 years ago

I'd like to host a imported style on GitHub on a static raw URL but would not want users of old versions of my user style to download potentially incompatible updates to the imported style

You can include the commit-hash or the version tag in the URL e.g. https://raw.githubusercontent.com/StylishThemes/GitHub-Dark/v1.20.62/themes/ambiance.min.css

@import statement

I think using @import inside usercss is a bad idea, which is contrary to self-containing purpose. It would be better to inline imported styles.

silverwind commented 6 years ago

Linking to a commit ref is something that would work for me, great idea.

I think using @import inside usercss is a bad idea

In my case I'd like to include a big blob of minified CSS which would be very distracting when editing the style by hand. Other valid reasons could include that someone wants to share code between their styles. It's very common to load external resources in userscripts, why not also in userstyles?

tophf commented 6 years ago

That's an interesting idea but maybe we should limit it to metadata keys to be closer to userscripts e.g. @import or @require or both. Not in the style code, I mean.

eight04 commented 6 years ago

someone wants to share code between their styles

It's common to share libraries across different scripts, but I doubt if it's a valid use case in CSS. Since CSS depends on the HTML structure, I don't think it is possible to create a "common library" that would work with different sites.

tophf commented 6 years ago

Hmm, off the top of my head, you can share fonts (and the declarations can have data URLs), styles for buttons, and other standard elements - not necessarily in one resource, but separately.

DanaMW commented 6 years ago

I share a lot of code to all site starting with buttons myself.

DanaMW commented 6 years ago

i did mine right from firefox's userchrome on out to every site i style so it's all uniform.

silverwind commented 6 years ago

Yes, a dedicated usercss header might also work. One point in favor of supporting it on @importis that it allows to dynamically load different styles when combined with media queries, but I doubt something like this has much use in an userstyle.

Another concern that was raised was that the cached CSS might not be easily accessible by the user, but I think this could be solved by showing which files get included during installation, so the user can review them before installation.

the-j0k3r commented 6 years ago

but I think this could be solved by showing which files get included during installation, so the user can review them before installation.

Showing them whenever user wants would be best in addition to that and allowing that to be beautified in case its minified.

eight04 commented 6 years ago

How do we process imported files? Concatenate them with the source code before running the preprocessor?

silverwind commented 6 years ago

Concatenate them with the source code before running the preprocessor?

I would concatenate them with a \n joiner, right after the user css header. I could also see having them fenced by comments, like /* start/end import from <url>*/. That way, CodeMirror could be configured to detect these import sections and code folding could be applied to them (folded in by default).

tophf commented 6 years ago

Er, no, that looks fragile in the sense that it's too easy to mangle the imported code via search/replace so we would have to exempt it. We could display a widget like the one we have for applies-to, and the widget would show the imported code in uhm something, like maybe an embedded readonly codemirror.

The actual import expansion would happen only internally, at saving/updating.

myfonj commented 6 years ago

Did a quick test if @import url() could be expanded to plain old static data URIs even when nested and it seems to work as expected (with paying attention to properly URIEncode what necessary considering depth):

<!doctype html>
<title>Nested dataURI CSS imports test</title>
<style>
@import url("data:text/css;here could be mentioned original URL and timestamp of retrieval,\
  @import url(%22data:text/css;...metadata,\
    @import url(%2522data:text/css,\
      @import url(%252522data:text/css,\
        p { font-style: italic; }\
      %252522);\
      p { text-decoration: underline; }\
    %2522);\
    p { color: white; }\
  %22);\
  p { background-color: black; }\
");
body { font-family: cursive; }
</style>
<p>This should be white on black underlined italic cursive,
i.e. basically the same outcome as if this document and sibling files contained
<pre>
/* style element content: */ @import url("a.css"); body { font-family: cursive; }
/* a.css file content: */ @import url("b.css"); body { background-color: black; }
/* b.css file content: */ @import url("c.css"); body { color: white; }
/* c.css file content: */ @import url("d.css"); body{ text-decoration: underline; }
/* d.css file content: */ body{ font-style: italic; }
</pre>

So it appears that target "processed" format could be such CSS that has zero external dependencies and could still be somewhat readable, without need to introduce extra descriptive /* comments */.