Welcome to 2019
[ikiwiki.git] / doc / todo / concatenating_or_compiling_CSS.mdwn
1 It would be great if IkiWiki could apply some sort of preprocessing to
2 CSS. I'm just "thinking out loud" at the moment, but I might write
3 a plugin.
4
5 The simplest starting point would be concatenating a list of files:
6
7 * The actiontabs and monochrome themes are not ready for use as-is;
8   the Makefile constructs the real stylesheet by concatenating the
9   anti-theme's CSS and the relevant theme's CSS. It would be better
10   if they could just drop a file in an underlay, and IkiWiki would
11   concatenate the anti-theme stylesheet and the theme's file.
12
13 * The blueview theme is the same, but the theme's CSS also starts
14   with a couple of stylesheets from YUI. IkiWiki could maybe
15   concatenate the anti-theme stylesheet, the two YUI stylesheets
16   and the blueview-specific part? Or maybe that's too complicated.
17
18 * The goldtype theme is the blueview theme with some overrides
19   added to the end. Again, IkiWiki could concatenate all the pieces.
20
21 * The [[plugins/contrib/album]] plugin needs to append some
22   stuff to the stylesheet, making its installation more involved
23   than it ought to be. If it could append the pieces by putting them
24   in an underlay, installation would just be a matter of "add
25   the files".
26
27 I'm not sure whether local.css should be concatenated too, or whether
28 it should be separate.
29
30 It would also be great if the same mechanism could be extended
31 to compile CSS-like languages like [[!debpkg ruby-sass desc=SASS]]
32 or [[!debpkg node-less desc=LESS]] down to CSS, but for dependency
33 reasons, I don't think the themes shipped with IkiWiki should rely on that.
34
35 If the compiled CSS ended up with a content-based filename (perhaps
36 ikiwiki/compiled-HASH.css where HASH is the (possibly truncated) MD5 or SHA1
37 hash of the content), that would mitigate stale CSS being served from cache
38 (as long as the HTML has a short expiry, which is desirable anyway),
39 and ikiwiki-hosting could maybe even do something like this to allow
40 long-term caching of the files with content-based names:
41
42     <LocationMatch /ikiwiki/compiled-[a-f0-9]+\.css>
43         ExpiresByType text/css "now plus 1 year"
44     </LocationMatch>
45
46 A similar mechanism could maybe be used to minify JavaScript.
47
48 ## vague syntax proposal: controlled by directive
49
50     \[[!css files="""
51         style.css
52         ikiwiki/plugin*.css
53         ikiwiki/theme*.css
54         local.css
55     """]]
56
57 * *css* directive, placed in any page, concatenates the given files
58   and uses them as the stylesheet for that page and its subpages,
59   replacing `<TMPL_VAR BASEURL>style.css`
60
61 * the files can be globs, which are sorted lexicographically within
62   a glob, and do not have to match anything (so it's OK if you don't
63   have anything that matches `plugin*.css`); "-" happens to sort
64   before ".", so theme-base.css would sort before theme.css,
65   which is nice to have
66
67 * the default would be `style.css`, then `ikiwiki/plugin*.css`,
68   then `ikiwiki/theme*.css` and maybe `local.css`, as in the
69   example above
70
71 * `style.css` would continue to be the anti-theme
72
73 * themes would ship `ikiwiki/theme.css` instead of `style.css`,
74   resulting in concatenation
75
76 * goldtype would ship `ikiwiki/theme-base.css` (which is a copy of
77   blueview, or a symlink to blueview if we can make symlinks safe)
78   and `ikiwiki/theme.css` (which is the goldtype additions)
79
80 * [[plugins/contrib/album]] would put its templates and
81   `ikiwiki/plugin-album.css` in an underlay
82
83 * any non-contrib plugin with complicated CSS requirements
84   could also move its CSS to an underlay
85
86 I think this could be done entirely in a plugin, except for this
87 change to `page.tmpl` to allow the `<style>`s to be overridden:
88
89     <TMPL_IF COMPILED_CSS>
90         <style type="text/css" href="<TMPL_VAR BASEURL><TMPL_VAR COMPILED_CSS>" />
91     <TMPL_ELSE>
92         <!-- ... what it does now ... -->
93     </TMPL_IF>
94
95 The plugin could also optionally minify its output, and either pass input
96 files through an external SASS/SCSS/LESS implementation according
97 to their extension, or have a hook system to do so.
98
99 People who want SASS/LESS would probably just do this in their top-level page:
100
101     \[[!css files="mywiki.less"]]
102
103 and do the inclusion/concatenation logic via @import.
104
105 Security consideration: the SASS/LESS compilers will read arbitrary local
106 files, so if you use those languages, ability to upload the appropriate
107 extension would have to be locked-down. Perhaps it's better to implement
108 this without that feature initially.
109
110 --[[smcv]]
111
112 > Although I understand the need to improve CSS inclusion, I wonder why you are
113 > proposing concatenating CSS rather than including them as several `<link
114 > type="text/css" href="FILE.css" rel="stylesheet">` lines
115 > in the header: unless I am missing something, I see this as far more simpler
116 > than concatenating them.
117 >
118 > This would imply that a template variable `CSS` is added to the page
119 > template, to be filled with those lines.
120 >
121 > Whatever solution is used, I agree that such a thing would be useful:
122 > adding CSS (rather than replacing the existing one) should be easier.
123 >
124 > -- [[Louis|spalax]]
125
126 >> One big request is more efficient than lots of small requests,
127 >> if we model the CSS as all changing equally infrequently.
128 >> In terms of bytes, each file needs some code in the HTML `<head>`,
129 >> plus the HTTP request and response headers, plus the actual file.
130 >> On the first page-view, a visitor will have to download all the CSS anyway
131 >> (one request/response pair per CSS file). On subsequent page-views, there
132 >> will be one request/"304 Not Modified" response per CSS file, unless the
133 >> CSS files can be marked "to be cached forever" (which can be done if
134 >> they have content-based filenames).
135 >>
136 >> In terms of time, [[!wikipedia HTTP_pipelining desc="according to Wikipedia"]]
137 >> browsers don't generally pipeline requests, so the page won't finish
138 >> loading until one round-trip time per uncached CSS file has elapsed.
139 >>
140 >> Having lots of small files with content-based filenames would be the
141 >> next best thing - not particularly efficient on a generic web server,
142 >> but they could at least be marked as "cache forever" in server
143 >> configuration. I'd be OK with doing that if it makes ikiwiki more
144 >> maintainable, but I don't think concatenating all the CSS at
145 >> compile time is actually going to be a problem in practice.
146 >> The individual small files are still going to be available
147 >> for the wiki operator to edit.
148 >>
149 >> If some CSS files change with a significantly different frequency,
150 >> *then* it might become worthwhile to separate them, but I don't
151 >> think that's the case (apart from possibly local.css, which is why
152 >> I'm not sure whether to include it in this).
153 >> --smcv
154
155 >>> I must admit that I am not aware of how those several CSS inclusion lines
156 >>> tend to make browsing less smooth. Please withdraw my comment.
157 >>>
158 >>> As you pointed out, CSS inclusion is more painful than it should be, and
159 >>> your proposal seems to answer that. Go ahead! --[[Louis|spalax]]