Skip to content

Loading…

.import(basePath) plugin to read and inline @imported stylesheets #32

Closed
wants to merge 1 commit into from

6 participants

@eknkc

Hi,

Created an @import disk read plugin (#24). It just goes in a depth first search and merges the css ast into current one. Not sure if it's the way you'd want to implement though. Feels kinda ugly.

@ForbesLindesay

+1000 for this feature, haven't had a chance to look at your implementation.

@ai
ai commented

It will need for me too, to move from Sass :).

@ai
ai commented

Maybe we need different keyword @include 'path'? But for me it’s OK now :).

@ForbesLindesay

Why does it need to be a different keyword? It'd be cool to have plugable name resolution so that you could do a node.js/npm style lookup of installed css.

@ai
ai commented

@ForbesLindesay it is just idea :-).

Real problem, that plugin must lookup in several dirs. For example, Rails has a lot of assets dirs.

@kristoferjoseph

+1 On the necessity of this plugin.

Any feedback yet on what would be needed to merge it?

@tj
rework member
tj commented

I wouldn't mind this one being a third-party plugin as well as far as the lookup techniques etc go, I don't think many people actually use vanilla @import anymore but there's also that being a collision as an issue. I wouldn't mind @import foo, @import ../foo/bar etc as things we touch and quoted ones remain vanilla, tough call. It also depends on the extname too, we use .styl because of css-whitespace and our stylus syntaxes

@kristoferjoseph

Are you saying you would be ok with:

@import ../fwee imports fwee.css and fwee.styl for inclusion in the current rework
@import "../fwee" or @import url("../fwee") would do the seldom used vanilla import

Does this work?

I feel like anyone interested in using rework would probably not be using vanilla imports though no?

@ForbesLindesay

Personally I'd much rather we handled the string based version. I.e. optimise the vanilla case so it can actually be used.

@kristoferjoseph

@ForbesLindesay I think we are talking about two flavors of "vanilla" here. For clarity the one I am talking about is the worst practices one where the @import URL is included by the browser. I feel that for this case it would be best to basically concat the files when reworked since most people would not want multiple http requests and each browser does something different with it.

There is a cool recommendation for the @import where you can specify which CSS file to load for the browsers current media query, but it isn't implemented and in its current state would slow page load a bit anyways. Rework could support this recommended functionality *somewhat by creating an @media block from the information in the @import https://developer.mozilla.org/en-US/docs/CSS/@import.

An issue with just adding the contents of another file is that rework processing starts to become order dependent, which I don't think is wanted. For instance if each file has a variable block at the top you need to make a call as to how to define scope. A common pattern I see with stylus users is they have their variables in a separate file all together and import them into files that use them. In the current rework spec I am not sure how this would work. Would you require duplicating variable definitions at the top of each file then process the variables at import time before inclusion? Would you merge variables? Would it be last in wins as far as overriding variable values?

@tj
rework member
tj commented

leaving out of core for now

@tj tj closed this
@anthonyshort

I actually think you could get away with not needing this if you're using something like Component. If your CSS is really modular you could probably get away with not caring about the order of the files and just concat everything and run Rework over it.

@tj
rework member
tj commented

yea you can definitely get away from it with a small makefile or other build tool. for some plugins like vars you'd have to do a single pass otherwise you lose all that data though hmm..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
34 Readme.md
@@ -85,6 +85,7 @@ $ rework -v webkit,moz < my.css > my.reworked.css
- [references](#references) — add property references support `height: @width` etc
- [mixin](#mixinobjects) — add custom property logic with mixing
- [extend](#extend) — add `extend: selector` support
+ - [import](#importpath) — read and inline imported stylesheets
### .extend()
@@ -629,6 +630,39 @@ yields:
}
```
+### .import(path)
+ Read and inline imported stylesheets relative to supplied base path.
+
+main.css:
+
+```css
+@import "imported.css"
+
+a {
+ color: yellow
+}
+```
+
+imported.css:
+
+```css
+span {
+ color: red
+}
+```
+
+yields:
+
+```css
+span {
+ color: red
+}
+
+a {
+ color: yellow
+}
+```
+
## Example
example.js:
View
76 lib/plugins/import.js
@@ -0,0 +1,76 @@
+
+/**
+ * Module dependencies.
+ */
+
+var css = require('css')
+ , fs = require('fs')
+ , path = require('path')
+ , utils = require('../utils');
+
+/**
+ * Read and inline imported stylesheets.
+ *
+ * main.css:
+ * @import "imported.css"
+ *
+ * a {
+ * color: yellow
+ * }
+ *
+ * imported.css:
+ * span {
+ * color: red
+ * }
+ *
+ * yields:
+ *
+ * a {
+ * color: yellow
+ * }
+ *
+ * span {
+ * color: red
+ * }
+ */
+
+module.exports = function(basepath) {
+ if (!basepath) basepath = process.cwd();
+
+ return function importPlugin(style, rework) {
+ var rules = [];
+ var files = {};
+
+ visit(style, basepath + path.sep + ".");
+ rework.obj.stylesheet.rules = rules;
+
+ function visit(style, file) {
+ if (files[file] == 'importing')
+ throw new Error('Import cycle detected on ' + file);
+ else if (files[file])
+ return;
+
+ files[file] = 'importing';
+
+ for (var i = 0; i < style.rules.length; i++) {
+ var rule = style.rules[i];
+ if (!rule.import) continue;
+
+ var filename = rule.import.replace(/url\(([^)]+)\)/g, function(_, url) {
+ return url;
+ });
+
+ filename = utils.stripQuotes(filename);
+ if (/^\s*http/.test(filename)) continue;
+ filename = path.resolve(path.dirname(file), filename);
+ if (!fs.existsSync(filename)) continue;
+ style.rules.splice(i--, 1);
+ visit(css.parse(fs.readFileSync(filename, 'utf8')).stylesheet, filename);
+ }
+
+ files[file] = 'imported';
+
+ rules = rules.concat(style.rules);
+ }
+ };
+};
View
1 lib/rework.js
@@ -104,3 +104,4 @@ exports.at2x = require('./plugins/at2x');
exports.url = require('./plugins/url');
exports.ease = require('./plugins/ease');
exports.vars = require('./plugins/vars');
+exports.import = require('./plugins/import');
View
5 test/fixtures/import-cycle-imported.css
@@ -0,0 +1,5 @@
+@import url('import-cycle.css');
+
+div {
+ color: blue;
+}
View
5 test/fixtures/import-cycle.css
@@ -0,0 +1,5 @@
+@import url('import-cycle-imported.css');
+
+a {
+ color: blue;
+}
View
3 test/fixtures/import-imported-2.css
@@ -0,0 +1,3 @@
+span {
+ color: yellow;
+}
View
5 test/fixtures/import-imported.css
@@ -0,0 +1,5 @@
+@import "import-imported-2.css";
+
+div {
+ color: blue;
+}
View
6 test/fixtures/import.css
@@ -0,0 +1,6 @@
+@import url('import-imported.css');
+@import 'import-imported-2.css';
+
+a {
+ color: blue;
+}
View
11 test/fixtures/import.out.css
@@ -0,0 +1,11 @@
+span {
+ color: yellow
+}
+
+div {
+ color: blue
+}
+
+a {
+ color: blue
+}
View
16 test/rework.js
@@ -230,6 +230,22 @@ describe('rework', function(){
})
})
+ describe('.import(path)', function(){
+ it('should read imported scripts', function(){
+ rework(fixture('import'))
+ .use(rework.import(__dirname + "/fixtures"))
+ .toString()
+ .should.equal(fixture('import.out'));
+ })
+
+ it('should detect import cycles', function(){
+ (function() {
+ rework(fixture('import-cycle'))
+ .use(rework.import(__dirname + "/fixtures"));
+ }).should.throw();
+ })
+ })
+
describe('.toString() compress option', function(){
it('should compress the output', function(){
rework('body { color: red; }')
Something went wrong with that request. Please try again.