Use .coffee to config .less in a package


#1

So I am building this UI theme called Graphite-UI. And I am fiddling around with .coffee to let the user have some options. Now I am totally new to coffeescript and I want to know if the following is even possible:
I want to have an option, say a simple boolean, that will change a setting in a .less file. Say we have a toggle for background color of the UI. If it is on, the @background-color in the less files changes to green, if it’s off the color will be red.
I know it is possible to solve it with a addition of a class, but I want to change it in the .less-file so other colors (based and that variable using lighten etc) change accordingly.


What's the risk of not-defining standard syntax variables?
#2

Less has js interpolation. So maybe you could have a less-vars.json file, and read it from less with fs.readFileSync('less-vars.json');? Then you would need to reload your less style every time you write to that file.


#3

Thanks! Let me try that, have to figure out how to access and write to a .json file though.


#4

You can do that from coffeescript easily:

fs = require 'fs'
fs.writeFileSync 'less-vars.json', JSON.parse(object)

The json file can be a file in your project directory


#5

Cool, so I got something like this in my .coffee:

applyThemeColoring = (useColors) ->
  if useColors
    fs = require 'fs'
    data = '{"theme": "blue"}';
    fs.writeFileSync 'less-vars.json', JSON.parse(data)

It triggers the code, but it gives me the permission denied error when trying to access the file. I put it in the project root folder.

EDIT: Also, I think this is super basic stuff, no? Is there a tutorial I should follow, instead of bothering you again? :smile:


#6

The path in the fs.writeFileSync should be relative to the coffeescript file. So assuming your coffeescript file is in project-root/lib/file.coffee, and the json file is indeed in the project root (project-root/less-vars.json), it should read this:

fs.writeFileSync '../less-vars.json', JSON.parse(data)

note the ../ at the start of the path.

The node api docs should provide you some information, though it could be expanded on in the future. I dont mind the bothering :smile:, but I’ll be away from my pc for the next few hours so you’ll be on your own (and the rest of this awesome community)


#7

Thinking about it, you probably don’t have permission to write to the file because the working directory is set to the atom application’s directory. Try

path = require 'path'
jsonPath = path.join __dirname, '..', 'less-vars.json'
fs.writeFileSync jsonPath, JSON.stringify(data)

Also the JSON.parse was wrong, you should JSON.stringify


#8

Yes this worked, thanks a bunch! Have a good one!


#9

One last thing, trying to run the js in less gives me a big crash.
I’m not familiar with this, and can’t find it anywhere in the less docs. I am getting a ‘unsafe-eval’ error.

@color: `function(){
  var fs = require("fs");
  var data = JSON.parse(fs.readFileSync("less-vars.json"));

  return data.theme;
  }`;

#10

Atom disables the use of eval and new Function, so embedding JS in your LESS file won’t work. Why not just write out a .less file and include it normally?

fs.writeFileSync 'vars.less', "@color: #{theme};\n"
@include 'vars.less'

#11

That’s clever! Why didn’t i think of that?


#12

oh man… that’s delightful simple. Clever. Thanks!


#13

Oh I so want this! There is some stuff I’ve been able to do in Isotope-UI with just classes and attributes, but it’s suboptimal to say the least.


#14

Yeah, I can also use this in my block cursor package. It’s so much easier than maintaining a <style> element’s sheet :smile:


#15

But how do we actually reload a stylesheet? I can’t seem to find anything in the docs


#16

I’ve been using atom.reload() but somehow that stopped working for me. However it wasn’t ideal anyway, since it completely reloaded atom. What would be better is reloading just the theme.

EDIT: Just changed my UI theme back and forth, and upon changing atom seems to be doing exactly what I need. Reloading just the styles. I should dig around how to trigger that action.


#17

I thought about that, but I’d rather reload just the one style from my package. Reloading the ui theme still makes the window flicker, and worse, on my 3-years-old laptop it makes the entire window completely unresponsive for about 5 seconds…


#18

You can use atom.themes.requireStylesheet:
https://github.com/atom/atom/blob/master/src/theme-manager.coffee#L227-L241

# remove the stylesheet if it is already loaded
@myStylesheet?.dispose()
# apply the stylesheet and store the disposable
@myStylesheet = atom.themes.requireStylesheet @myStylesheetPath

If you’d like to see it in context you can look at how I do it: https://github.com/Alchiadus/base16-syntax/blob/master/lib/base16.coffee (some calls might be deprecated, I hope I can update it very soon).


#19

Thanks! I’m doing it like this now:

atom.themes.removeStylesheet @myStylesheet
atom.themes.requireStylesheet @myStylesheet

A bit weird this can not be done in atom.styles but only from atom.themes


#20

If I remember correctly using that instead of dispose() fails in the following scenario:

  • apply stylesheet1
  • remove stylesheet1 and apply stylesheet2
  • remove stylesheet2 and reapply stylesheet1
    Stylesheet1 won’t be applied (since somewhere the Theme Manager thinks it is still loaded I believe).

However, a bigger problem is the following commit:


This seems to indicate atom.themes.requireStylesheet is actually deprecated, but Deprecation Cop does not mention it nor can I find what the new way to load a stylesheet is. If it will eventually simply be removed it would be very hard (impossible?) to manually reload stylesheets. Does anyone have an idea what the new preferred method is?