Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9ec0e8a
got a very simple standalone css module compiler working
geelen Oct 25, 2015
66dc05a
Merge branch 'vendor-css-modules-compiler'
tomasc Oct 29, 2016
04d5494
core build
tomasc Oct 29, 2016
fef4dae
reorg
tomasc Oct 29, 2016
f3020b3
works
tomasc Oct 30, 2016
758f3c0
works
tomasc Oct 30, 2016
753da37
update
tomasc Oct 30, 2016
0083cdf
cleanup
tomasc Oct 30, 2016
6399577
working core
tomasc Nov 5, 2016
4bac145
working core
tomasc Nov 5, 2016
5a18bc8
add badges
tomasc Nov 5, 2016
5b7cc87
doc
tomasc Nov 5, 2016
c5212eb
upd
tomasc Nov 5, 2016
24d69a8
js
tomasc Nov 5, 2016
c63bd73
note
tomasc Nov 5, 2016
1d8db08
Update node_async_runner.js
tomasc Nov 5, 2016
b95b50d
Travis
tomasc Nov 5, 2016
1c995f2
fix
tomasc Nov 5, 2016
3b27f8b
update
tomasc Nov 5, 2016
85db8ee
upd
tomasc Nov 5, 2016
3ce71fd
Update index.js
tomasc Nov 5, 2016
798913f
fake pathFetcher
tomasc Nov 6, 2016
08cc2c8
working js
tomasc Nov 6, 2016
a3b2e9a
base works
tomasc Nov 6, 2016
2b062e6
upd
tomasc Nov 6, 2016
acaac79
rebuild for plain js
tomasc Nov 6, 2016
d223df8
works
tomasc Nov 6, 2016
11b6c92
improved asset finder
tomasc Nov 6, 2016
efb8892
upd
tomasc Nov 6, 2016
ccef282
upd
tomasc Nov 6, 2016
6dc2421
Fix: cross-file composes
tomasc Nov 7, 2016
dffc7d9
global by default
tomasc Nov 7, 2016
0eedf2d
cleanup readme
tomasc Nov 7, 2016
2c9bc51
test global classes
tomasc Nov 7, 2016
cead939
bump node version
tomasc Nov 7, 2016
2a08228
update README
tomasc Nov 7, 2016
4924fb7
update node
tomasc Nov 7, 2016
9bb2847
bundle
tomasc Nov 7, 2016
eb6c08a
simplify
tomasc Nov 7, 2016
ed0156e
add comment
tomasc Nov 7, 2016
f873fb6
refactor namespace
tomasc Nov 7, 2016
288d9c8
refactor with cache
tomasc Nov 7, 2016
ef3a406
nested
tomasc Nov 7, 2016
416aabc
Change: refactor to support .*m extensions
tomasc Nov 7, 2016
b3659da
Update README.md
tomasc Nov 8, 2016
ab5238e
Update README.md
tomasc Nov 8, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
/doc/
/pkg/
/tmp/
/test/dummy/tmp/
/test/dummy/log/
node_modules
*.log
21 changes: 21 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
sudo: false
language: ruby
script: 'bundle exec rake'

rvm:
- 2.2.5

env:
- TRAVIS_NODE_VERSION='6.8.1'

before_install:
- gem install bundler -v 1.12.5
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION
- npm install

notifications:
email:
recipients:
- mail@tomascelizna.com
on_failure: change
on_success: never
4 changes: 3 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
source "https://rubygems.org"
source 'https://rubygems.org'

# Specify your gem's dependencies in cssm-rails.gemspec
gemspec

gem 'rb-readline'
78 changes: 74 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# CSS Modules for Rails

[![Build Status](https://travis-ci.org/tomasc/cssm-rails.svg)](https://travis-ci.org/tomasc/cssm-rails) [![Gem Version](https://badge.fury.io/rb/cssm-rails.svg)](http://badge.fury.io/rb/cssm-rails)

A Rails (Sprockets) wrapper on CSS Modules (respective the [CSS Module Loader Core](https://github.com/css-modules/css-modules-loader-core)).
It is a minimal and slightly naïve implementation at the moment (for example calling `node` command directly via command-line). Pull requests are more than welcome.

**A current drawback of an implementation of CSS Modules in Rails is, that it makes views dependent on stylesheets. Currently there is no way how to include digests of relevant stylesheet files with Rails partial digests. This in turn renders this solution unusable in connection with so called russian-doll-caching, since changes to stylesheet assets won't bust the view cache. Ideas and solutions welcome.**

## Installation

Add this line to your application's Gemfile:
Expand All @@ -10,27 +17,90 @@ gem 'cssm-rails'

And then execute:

$ bundle
```sh
$ bundle
```

Or install it yourself as:

$ gem install cssm-rails
```sh
$ gem install cssm-rails
```

## Requirements

This gem requires Node to be installed.

## Usage

Put foo.cssm in your app/assets/stylesheets directory with `.bar { color: red; }`. Use `<div class="<%= cssm "foo:bar" %>">` in your views. `//= require cssm` in then `CSSM.foo.bar` to use from javascript.
Files with `*.cssm`, `*.sassm`, `*.scssm` will be processed for CSS modules.
Files with `*.css`, `*.sass`, `*.scss` extensions will remain unchanged.

```css
/* common.cssm */
.bg { /* this class will be transformed to `.common_bg_HASH` */ };
```

```css
/* event.cssm */
.title {
composes: bg from './common.cssm';
/* this class will be transformed to `.event_title_HASH`,
the outcome of the `cssm` helper will then be `event_title_HASH common_bg_HASH`
*/
}
```

### Helpers

The `cssm` helper outputs css module classes:

```ruby
cssm(file_name, class_name)
```

For example:

```ruby
cssm('event', 'title') # => 'event_title_HASH common_bg_HASH'
```

The `cssms` outputs class selector:

```ruby
cssms('event', 'title') # => '.event_title_HASH.common_bg_HASH'
```

These are helpful to generate module classes in views:

```ruby
<p class="<%= cssm 'event', 'title' %>"> # => <p class="event_title_HASH common_bg_HASH">
event title
</p>
```

And selectors in JS:

```js
$("<%= cssms 'event', 'title' %>"); // => $('.event_title_HASH.common_bg_HASH')
```

## Development

After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).

### Rebuilding CSS Modules JS

```sh
bundle exec rake vendor_build
```

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/css-modules/cssm-rails.

## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).

24 changes: 23 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
require "bundler/gem_tasks"
require 'bundler/gem_tasks'
require 'rake/testtask'

Rake::TestTask.new(:test) do |t|
t.libs << 'test'
t.libs << 'lib'
t.test_files = FileList['test/**/*_test.rb']
end

task default: :test

desc 'rebuild the vendored postcss-modules'
task :vendor_build do
`cd vendor/src && npm install`
`cd vendor/src && npm run bundle`

# re-enable the fs module (which would be removed by browserify if uncommented)
bundle = File.join(__dir__, 'vendor/bundle.js')
content = File.read(bundle).gsub("// var fs = require('fs');", "var fs = require('fs');")
File.open(bundle, 'w+') do |output_file|
output_file.write(content)
end
end
38 changes: 19 additions & 19 deletions cssm-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,29 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require 'cssm/rails/version'

Gem::Specification.new do |spec|
spec.name = "cssm-rails"
spec.name = 'cssm-rails'
spec.version = CSSM::Rails::VERSION
spec.authors = ["Samuel Cochran"]
spec.email = ["sj26@sj26.com"]
spec.authors = ['Tomas Celizna']
spec.email = ['mail@tomascelizna.com']

spec.summary = %q{CSS Modules for Rails}
spec.description = %q{A CSS Module is a CSS file in which all class names and animation names are scoped locally by default. All URLs (url(...)) and @imports are in module request format (./xxx and ../xxx means relative, xxx and xxx/yyy means in modules folder, i. e. in node_modules).}
spec.homepage = "https://github.com/css-modules/cssm-rails"
spec.license = "MIT"

# Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
# delete this section to allow pushing this gem to any host.
if spec.respond_to?(:metadata)
spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
else
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
end
spec.summary = 'CSS Modules for Rails'
spec.description = 'A CSS Module is a CSS file in which class names and animation names are scoped locally.'
spec.homepage = 'https://github.com/css-modules/cssm-rails'
spec.license = 'MIT'

spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
spec.bindir = "exe"
spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
spec.require_paths = ["lib"]
spec.require_paths = ['lib']

spec.add_dependency 'rails'
spec.add_dependency 'sassc'
spec.add_dependency 'sassc-rails'
spec.add_dependency 'sprockets'

spec.add_development_dependency "bundler", "~> 1.10"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency 'bundler', '~> 1.10'
spec.add_development_dependency 'minitest', '~> 5.0'
spec.add_development_dependency 'minitest-rails'
spec.add_development_dependency 'minitest-rails-capybara'
spec.add_development_dependency 'rake', '~> 10.0'
end
3 changes: 1 addition & 2 deletions lib/cssm.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
module CSSM
end
require_relative 'rails/rails'
35 changes: 30 additions & 5 deletions lib/cssm/rails.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
require "cssm/rails/version"

require "cssm"

module CSSM
module Rails
# Your code goes here...
ROOT_PATH = __dir__

autoload :Sprockets, 'cssm/rails/sprockets'

def self.process(css, opts = {})
params = {}
processor(params).process(css, opts)
end

def self.install(assets, params = {})
Sprockets.register_processor(processor(params))
Sprockets.install(assets)
end

def self.uninstall(assets)
Sprockets.uninstall(assets)
end

def self.processor(params = {})
Processor.new(params)
end
end
end

require_relative 'rails/asset'
require_relative 'rails/processor'
require_relative 'rails/result'
require_relative 'rails/view_helper'

require_relative 'rails/railtie' if defined?(Rails)

require_relative 'rails/version'
33 changes: 33 additions & 0 deletions lib/cssm/rails/asset.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module CSSM
module Rails
class Asset < Struct.new(:name, :options)
def initialize(name, options = {})
super(name, options)
end

def path
@path ||= paths.flat_map do |path|
Dir.glob("#{path}/**/#{name}.{#{extensions.join(',')}}")
end.first
end

def css
@css ||= File.read(path)
end

def digest
@digest ||= Digest::MD5.hexdigest(css)
end

private

def extensions
options.fetch :extensions, %w(cssm sassm scssm)
end

def paths
@paths ||= ::Rails.application.config.assets.paths
end
end
end
end
23 changes: 23 additions & 0 deletions lib/cssm/rails/processor.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module CSSM
module Rails
class Processor < Struct.new(:params)
BUNDLE_JS_PATH = File.join(ROOT_PATH, '../..', 'vendor/bundle.js')

def initialize(params = {})
super(params)
end

def process(css, opts = {})
filename = opts.fetch(:from, nil)

bundle_js_args = Shellwords.escape(BUNDLE_JS_PATH)
css_arg = Shellwords.escape(css)
filename_arg = Shellwords.escape(filename.to_s)

result = JSON.parse `node #{bundle_js_args} #{css_arg} #{filename_arg}`

Result.new(result['injectableSource'], result['exportTokens'])
end
end
end
end
52 changes: 52 additions & 0 deletions lib/cssm/rails/railtie.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
require 'sassc-rails'
require 'sprockets/railtie'

begin
module CSSM
module Rails
class Railtie < ::Rails::Railtie
config.cssm = ActiveSupport::OrderedOptions.new

if config.respond_to?(:annotations)
config.annotations.register_extensions("scssm", "sassm") { |annotation| /\/\/\s*(#{annotation}):?\s*(.*)$/ }
end

initializer :setup_sass, group: :all do |app|
config.assets.configure do |env|
if env.respond_to?(:register_transformer)
env.register_transformer 'text/sass-modules', 'text/css', SassC::Rails::SassTemplate.new
env.register_transformer 'text/scss-modules', 'text/css', SassC::Rails::ScssTemplate.new
end

if env.respond_to?(:register_engine)
[
['.sassm', SassC::Rails::SassTemplate],
['.scssm', SassC::Rails::ScssTemplate]
].each do |engine|
engine << { silence_deprecation: true } if ::Sprockets::VERSION.start_with?("3")
env.register_engine(*engine)
end
end
end
end

initializer :cssm_rails_view_helpers do
ActionView::Base.send :include, CSSM::Rails::ViewHelper
end

if config.respond_to?(:assets) && !config.assets.nil?
config.assets.configure do |env|
CSSM::Rails.install(env, {})
end
else
initializer :setup_cssm_rails, group: :all do |app|
if defined? app.assets && !app.assets.nil?
CSSM::Rails.install(app.assets, {})
end
end
end
end
end
rescue LoadError
end
end
13 changes: 13 additions & 0 deletions lib/cssm/rails/result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module CSSM
module Rails
class Result < Struct.new(:injectable_source, :export_tokens)
def initialize(injectable_source, export_tokens)
super(injectable_source, export_tokens)
end

def to_s
injectable_source
end
end
end
end
Loading