stackcss / sheetify Goto Github PK
View Code? Open in Web Editor NEW:sparkles: Modular CSS bundler for browserify
License: MIT License
:sparkles: Modular CSS bundler for browserify
License: MIT License
Probably should list here once template strings land
When you use a template in your tagged template string css, the browserify transform breaks.
var aColor = '#fff'
var css = sf`.some-class {
background-color: ${aColor};
}`
CssSyntaxError: /Users/bret/repos/hyperamp/renderer/index.js:3:2: Unknown word while parsing file: /Users/bret/repos/hyperamp/renderer/index.js
1 | .some-class {
2 | background-color: ,;
> 3 | }[object Object]
| ^
I started down the road of correcting the in-node implementation, but we are going to have to statically analyze the template string during the transform somehow. I'm not too familiar with this kind of thing. Any ideas?
This is related to #54 but specific to the way template variables are busted right now vs how :host
gets used.
how would you set up a module to work with sheetify?
Hi!
I am trying to implement themes for parameters manager with sheetify, and due to namespacing css sheetify is ideal for that.
The only issue is that whenever theme is changed, old theme’s css needs to be deleted, which is unclear how can be done with insert-css, here’s a ticket.
Is there any way to get css string without insert-css being engaged?
Thanks.
I'm using "babel-preset-es2015": "^6.9.0" with "babelify": "^7.3.0", and import sf from 'sheetify';
doesn't work (5.0.3 of sheetify). I get:
Uncaught TypeError: (0 , _sheetify2.default) is not a function
1.on-load @ google-map.js:4
s @ _prelude.js:1
(anonymous function) @ _prelude.js:12
../components/google-map @ index.js:3
s @ _prelude.js:1
e @ _prelude.js:1
(anonymous function) @ _prelude.js:1
First example, the prefix
value does not match the "printed" markup.
.[[[ _60ed23ec9f ]]] h1 {
text-align: center;
}
And the rendered HTML includes the namespace:
<section class="[[[ _60ed23e ]]]">
<h1>My beautiful, centered title</h1>
</section>
What changes need to happen going forward? Stuff I'm currently thinking about doing:
myth
)require('mystyle.css
) -> inline-string with sheetify transforms applied. Not sure if it should be a separate project though (sheetifyify
?); I like the idea of having a single module to rule them all though.What else would be nice to have?
Be able to do this:
const sheetify = require('sheetify')
const http = require('http')
http.createServer((req, res) => {
const s = sheetify(__dirname + '/index.css')
s.bundle().pipe(res)
}).listen()
I have the following:
const sf = require('sheetify')
const prefix = sf`
h1 {
text-align: center;
}
`
console.log(prefix)
I'm guessing it gets transformed into some code that includes require('insert-css')
– this won't work unless my project explicitly installs that as a dependency. Due to npm3 flattening, this might not be immediately obvious in some projects. 😄
Would be really nice to get rid of the special :host selector, so prefixed styles could be used in host and non-hosts element without having to apply specific styles to :host.
I may be doing something wrong.
sheetify styles/app.css > bundle.css
/home/jacob/example-css-npm/node_modules/sheetify/node_modules/style-deps/node_modules/css/lib/parse/index.js:69
throw err;
^
Error: missing '{' near line 2:1
at error (/home/jacob/example-css-npm/node_modules/sheetify/node_modules/style-deps/node_modules/css/lib/parse/index.js:64:15)
Did a bit of debugging yesterday, and I think we're messing up the nodes slightly hah
From #32
It appears when piping to an external stream, things can sometimes go wrong. First read goes well, but then sometimes it fails on write after end
. I feel this has something to do with events not being read correctly (e.g. perhaps a conflict with watchify
). Opening an issue to gather more details - this might very well be userland, but then better docs are required
want to be able to something like:
function render (props) {
return h('div.' + prefix, {
textContent: 'hello world!'
})
}
:hover {
color: green;
}
but instead had to do:
function render (props) {
return h('div.' + prefix, [
h('div.thing', {
textContent: 'hello world'
})
])
}
.thing:hover {
color: green;
}
or am i missing something?
postcss has quite the list of plugins available, perhaps it would be wise to leverage that. I'd be mostly interested in loading the cssnext
pack:
Probably want to find a middleground between the approaches in css-modules and glslify ✨. Imo CSS could use some modularity.
As mentioned in #8 we need to think of a way to reliably handle semver. In CSS everything is globally spaced so different orders of importing can cause different results. We need a way of handling different semver versions reliably / transparently, however that may be.
needs example cases
I could be wrong but the following maybe related #48 #69
I am running budo
on the following JS with sheetify/transform
setup in package.json
.
var sheetify = require('sheetify');
var prefix = sheetify`
div {
color: #F0F;
}
.A {
color: #FF0;
}
`;
var container = document.createElement('div');
container.className = prefix;
container.innerHTML = `
<div>
<div>HELLO</div>
<div class="A">WORLD!</div>
</div>
`;
document.body.appendChild(container);
If I make a syntax error in CSS such as remove a closing curly brace I get the following stack trace:
/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/lazy-result.js:177
if (this.error) throw this.error;
^
CssSyntaxError: <css input>:5:3: Unclosed block
at Input.error (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/input.js:61:22)
at Parser.unclosedBlock (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/parser.js:466:26)
at Parser.endFile (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/parser.js:348:39)
at Parser.loop (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/parser.js:86:14)
at parse (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/parse.js:26:12)
at new LazyResult (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/lazy-result.js:61:24)
at Processor.process (/Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/postcss/lib/processor.js:34:16)
at /Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/sheetify/index.js:41:13
at /Users/mikkohaapoja/Documents/Learning/test-sheetify/node_modules/sheetify/index.js:52:7
When this error is thrown it will kill budo
.
So apparently @hughsk wrote this a couple of years back, but it's definitely better thought out than the function I wrote - I reckon we should use it
Tests should answer this but the build is currently failing. From what I can tell, if I don't pass { global: false }
I don't get my styles namespaced.
offending code here
evalmachine.<anonymous>:8
var elem = document.createElement('style');
^
ReferenceError: document is not defined
at module.exports (evalmachine.<anonymous>:8:16)
at Object.2.insert-css (evalmachine.<anonymous>:28:39)
at s (evalmachine.<anonymous>:1:254)
at e (evalmachine.<anonymous>:1:425)
at evalmachine.<anonymous>:1:443
at ContextifyScript.Script.runInNewContext (vm.js:18:15)
at Object.exports.runInNewContext (vm.js:49:17)
at parseBundle (/home/travis/build/stackcss/sheetify/test/prefix.js:43:10)
at /home/travis/build/stackcss/sheetify/node_modules/browserify/index.js:776:13
at ConcatStream.<anonymous> (/home/travis/build/stackcss/sheetify/node_modules/concat-stream/index.js:36:43)
is there a way too put this in a .pipe() in gulp?
my use case is i want a local file to be watched and on file change for my css to be re-bundled.
Getting the following when babelify
is the first transform. Does not occur when babelify
is defined after sheetify
.
path.js:8
throw new TypeError('Path must be a string. Received ' +
^
TypeError: Path must be a string. Received undefined
at assertPath (path.js:8:11)
at Object.posix.join (path.js:479:5)
at walk (/projects/mattdesl.github.com/node_modules/sheetify/transform.js:144:14)
at walk (/projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/index.js:49:9)
at /projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/index.js:46:17
at forEach (/projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/node_modules/foreach/index.js:12:16)
at walk (/projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/index.js:34:9)
at /projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/index.js:41:25
at forEach (/projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/node_modules/foreach/index.js:12:16)
at /projects/mattdesl.github.com/node_modules/sheetify/node_modules/falafel/index.js:39:17
I'm quite fond of hyperx, and how they use template strings. Might be cool to support them too in sheetify, e.g.
const vdom = require('virtual-dom')
const hyperx = require('hyperx')
const sf = require('sheetify')
const hx = hyperx(vdom.h)
const prefix = sf`
h1 {
text-align: center;
}
`
const tree = hx`
<section className=${prefix}>
<h1>My beautiful, centered title</h1>
</section>
`
console.log(vdom.create(tree).toString())
Does this make sense? Am I mad? I feel like this might be a bit too much / we really need to start thinking of how to consolidate the API as currently there's already too many ways of doing things haha, though this might be very useful.
@helveticade pointed out that inspecting HTML with just hashes doesn't relay a lot of information per-se; when debugging having something like the file filename / dirname available is neat; perhaps we can expose a hook for people to create their own prefix (in addition to the hash, which guarantees uniqueness). Thoughts?
I'd like to be able to do:
var sf = require('sheetify-js')
var className = sf({
foo: {
fontSize: 20
}
})
This seems like it really doesn't need to be in Sheetify core, it can just be a wrapper. Similar to sheetify-sass, there can be sheetify-js.
I could implement this, but first I need to find a good library for transforming a json object to css. Does it exist? I've had a hard time finding anything good.
What modules are we missing? For me the ones I'd like to pull in are:
$var
expander (so we can ditch sass at work)Hi @yoshuawuyts!
npm install sheetify
gives
+-- UNMET PEER DEPENDENCY insert-css@^0.2.0
`-- [email protected]
+-- [email protected]
| `-- [email protected]
`-- [email protected]
`-- [email protected]
`-- [email protected]
That would not be bad but running browserify gives Cannot find module 'insert-css' from 'C:\Users\dmitry\Dropbox\Projects\gl-spectrum'
.
Why inner-css
dependency is considered peer, when it is critical to run sheetify?
Hi @yoshuawuyts!
I am giving a try to sheetify in gl-spectrum and constantly stumbling on the following issue.
I use budo for developing, and sheetify is enabled as "browserify": {"transform": ["sheetify/transform"]}
field in package.json
. Styles are connected as follows:
var sf = require('sheetify');
var cssClass = sf('./index.css');
function Spectrum () {
...
this.container.classList.add(cssClass);
...
}
The problem is that each time when I have to change anything in the index.css
, I have to restart budo, which is quite annoying tbh.
Is there any sort of workaround, or it is not the sheetify’s concern at all, but rather budo’s?
I might mistaken, but that is not the same for glslify, it updates consistently without server restart.
Thanks.
Example:
/* comment.css */
:host .header {
color: blue;
}
/* article.css */
:host .header {
color: red;
}
<article class="_article-hash">
<h1 class="header">Article title</h1>
<section class="comments">
<article class="_comment-hash">
<h2 class="header">Comment title</h2>
</article>
<section>
</article>
Comment header will be either red or blue, depending on the order of file inclusion. You can guard with >
selectors, but this makes your CSS dependent on the exact DOM structure.
Shadow DOM naturally does not suffer from this.
BEM does not suffer from this, due to using unique names.
CSS Modules does not suffer from this, due to rewriting all class names.
Vue implementation of scoped styles does not suffer from this, due to rewriting HTML too and using different prefixing technique (<div class="header" _article-hash>
and .header[_article-hash]
).
update 2016/03/14: :root
isn't a very good idea; we should just rely on JS vars instead.
update 2016/11/16. scratch that, :root
in moderate usage is a great idea, as long as a postprocessor can handle it (which it can now)
What do you think of making :root
elements the transport for variables and such? Root would never be prefixed, and passed down to child elements so they can read values from it during compilation. Perhaps we should also do this for @custom-media
selectors so breakpoints are passed down too? (example)
Opinions?
client-main.js
const sf = require('sheetify')
sf`
:root {
--color-bg-primary: blue;
}
`
require('./client-sidebar')
client-sidebar.js
const sf = require('sheetify')
sf`
:host > h1 {
background-color: var(--color-bg-primary);
}
`
supersedes #31
sheetify
's api is a bit all over the place. Currently we support:
js
and package.json
styles)When sheetify was first written, it served as an alternative to LESS
and SASS
. The current version aims to provide namespaces as a browserify
transform and import
dependency resolution to arbitrary preprocessors (never fully implemented).
I propose we refactor the api to work optimally for the current goals. This way we can shrink the code base, provide a more coherent story to users and generally improve the usefulness of the tool.
The changes I'd like to see are:
cli
api - other preprocessors have cli's that can be used directlyjs callback
and js stream
api - other preprocessors have api's that can be used directlyreset.css
) (iirc @hughsk had ideas for this)sheetify
can no longer be used as a linker; this was never fully implemented but would no longer be possiblesheetify
becomes dependent on browserify
- imo that's a good thing as that is where the value is added. webpack
support could be added through an external browserify -> webpack
adapterI hope I'm making sense with this all; I'd be happy to see sheetify
progress down the path to simplification.
cc/ @hughsk @ahdinosaur I'd be keen to hear your thoughts on this
trying to use the :nth-child
pseudo-selector and its not working as expected:
.row {
border: 1px solid black;
}
.row:nth-child(odd) {
background-color: #eee;
}
<div>
<div class="row">yo!</div>
<div class="row">dude</div>
</div>
However, when you do this with sheetify, the transformed CSS looks like:
._ffdf2d5a .row {
border: 1px solid black;
}
._ffdf2d5a .row:nth-child(._ffdf2d5a odd) {
background-color: #eee;
}
Which does not apply the rule to the odd nth-children. If you add a rule in your inspector omitting the ._ffdf2d5a
prior to odd
:
._ffdf2d5a .row:nth-child(odd) {
background-color: #eee;
}
It works as expected.
From #32 (comment)
an open question is whether we specify any default plugins, such as what
css-modulesify
does. specifically i'm thinking ofpostcss-import
, perhaps also a way to pass values around (like this but in our own way).
I reckon including postcss-import
is a good call; if any other plugins should be included too this would be the right place to discuss.
I have the following problem. I'm using two npm packages that use css defined on their package.json
files. The first one, tachyons, defines in the main and style section a path to the css. The second one, leaflet, define a js file in his main section and a css file in his style section. When I use them with sheetify, tachyons work, but leaflet fails. I'm using it like this.
const sf = require('sheetify')
sf('tachyons', { global: true })
sf('leaflet', { global: true })
That result in
Error: Cannot find module 'leaflet' from '/home/yerko/Dev/partes/src' while parsing file: /home/yerko/Dev/partes/src/app.js
So, am I doing it wrong? or should sheetify recognize leaflet css file?
From #32
Scoping styles to components is ideal as a transform, but sometimes global files must be included too (such as reset.css
). These files shouldn't be namespaced, but should be included in the resulting bundle.
If you're receiving the error
Uncaught TypeError: Cannot read property 'isFile' of undefined
You probably forgot to tell browserify/budo to use the sheetify/transform
.
browserify index.js -t sheetify/transform -o bundle.js
budo index.js -- -t sheetify/transform
I feel like I run into this error every few days and spend 20 minutes debugging before slapping my forehead. Next time, I'll search the issues and find this thread.
Are there plans to add a watch option?
So far I've been using chokidar-cli to do something like this:
chokidar 'css/*.css' -c 'npm run bundle-css'
Where the bundle-css
script is the sheetify
command.
That works fine for now. But being able to watch changes with -w
would be neat.
It'd be nice to get this and style-deps
out there in some capacity, have a couple of side projects I'd like to try use it in too. What else would we need to get sorted before we go ahead with it?
Hi! What do you think about @apply
support?
:root {
--awesomeComponent-theme: {
color: white;
background: black;
}
}
.awesomeComponent {
width: 100%;
margin: 0 auto;
@apply --awesomeComponent-theme;
}
https://www.chromestatus.com/feature/5753701012602880
ref: #87
if we can use plugin, resolve with postcss-apply.
Reopening this as a follow up to #21.
Currently watchify
kinda works with sheetify - since only new .js
files are recompiled by browserify, just recreating new files from these events will cause incomplete files on recreation.
Maybe it's what #21 suggested, but I think the solution to this might be to send the stream in opts.out
a "file" event so that it knows which are the new files, and which should be cached. I don't know how this would work on the cli tho in conjunction to watchify
- should we perhaps have plugins
such as browserify
to make this work? I'm not sure, hah.
Thanks!
I removed it just to push v3 out, think we should restore it soonish (':
Why did the global
option disappear in a3a3ff591832802c924cc6652e228ee19af2335e? AFAICT, styles are now global unless you prefix them with :host
. The current README also indicates this, in that :host
is used consequently in order to namespace styles.
Is the reason for this change documented anywhere?? Reason I'm asking is my project broke with an upgrade to sheetify, and I had no idea why my styles were no longer namespaced.
use case is using sheetify
in a "universal" / "isomorphic" app, so as both a browserify transform and in node.
in node, if i want to do
const sheetify = require('sheetify')
const prefix = sheetify('./index.css')
in anywhere other than the same directory as process.cwd()
, i'll get an error
Error: Cannot find module './index.css' from '/cwd'
at Function.module.exports [as sync] (/cwd/node_modules/style-resolve/node_modules/resolve/lib/sync.js:32:11)
at Function.resolveSync [as sync] (/cwd/node_modules/style-resolve/index.js:22:19)
at sheetify (/cwd/node_modules/sheetify/index.js:20:22)
at Object.<anonymous> (index.js:5:16)
at Module._compile (module.js:435:26)
at loader (/cwd/node_modules/babel-register/lib/node.js:127:5)
at require.extensions.(anonymous function) (/cwd/node_modules/babel-register/lib/node.js:137:7)
at Object.nodeDevHook [as .js] (/cwd/node_modules/node-dev/lib/hook.js:43:7)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:311:12)
sure i could do
const sheetify = require('sheetify')
const prefix = sheetify('./index.css', { basedir: __dirname })
but this seems silly...
i propose we default basedir
to the caller path instead of process.cwd()
. it's already being defaulted to process.cwd()
in the cli module and path.dirname(filename)
in the transform module, will need to default to something in the stream module.
thoughts?
Hiya,
From looking at the source, I saw that postcss
is used internally, but it’s not possible to use any of the available plugins with sheetify. Instead, there is a separate plugin mechanism implemented.
Would it be possible to also allow postcss plugins?
I have a few components that are similar and I'd like to share styles between rather than copying & pasting the styles into each component. So I put the shared styles into a .css
file and imported them into each component via sf('path/to/styles.css')
. Fortunately sheetify seems to know it's the same file so it uses the same class name for both components. But it still puts the contents of the .css
file into the <head><style>
tag twice:
Is that expected behaviour? Is there a better way to accomplish what I'm trying to do? The only other thing I can think of is to put the css on the parent element, but that feels like unnecessary coupling. Or use insert-css
to just add css like olden times.
Been using sheetify for a while now, and feel there's some rough edges still. In this issue I try and outline which problems I've been experiencing, and suggest solutions on how to fix 'em. Comments and suggestions super welcome; if we need to break stuff this is the place to mention it
insert-css
as a peer dep is hella annoying and probably makes for a not-so-great user experience - using sheetify
right now doesn't "just work" and yeah it would be cool if it didinsert-css
a file in sheetify that can be required in, removing the peer dep (prcss-extract
to also detect the sheetify/insert
(minor patch; just pick up more files):host
properties are prefixedAnd that's it. Suggestions and thoughts super welcome!
Getting this when using an invalid filename to sheetify function:
assert.js:89
throw new assert.AssertionError({
^
AssertionError: filename must be a string
at parseCss (/projects/mattdesl.github.com/node_modules/sheetify/index.js:31:10)
at sheetify (/projects/mattdesl.github.com/node_modules/sheetify/index.js:23:17)
at nr (/projects/mattdesl.github.com/node_modules/browserify/node_modules/module-deps/index.js:297:23)
at /projects/mattdesl.github.com/node_modules/browserify/node_modules/resolve/lib/async.js:44:21
at ondir (/projects/mattdesl.github.com/node_modules/browserify/node_modules/resolve/lib/async.js:187:31)
at onex (/projects/mattdesl.github.com/node_modules/browserify/node_modules/resolve/lib/async.js:93:22)
at /projects/mattdesl.github.com/node_modules/browserify/node_modules/resolve/lib/async.js:24:18
at FSReqWrap.oncomplete (fs.js:82:15)
And it kills budo and other tools. Instead, might be better for the transform to emit an error
event so budo and similar tools can catch it and display this error in the browser.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.