browserify-rails 0.0.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +1 -0
  4. data/LICENSE.txt +2 -2
  5. data/README.md +83 -15
  6. data/Rakefile +26 -0
  7. data/browserify-rails.gemspec +21 -16
  8. data/lib/browserify-rails.rb +8 -0
  9. data/lib/browserify-rails/browserify_error.rb +5 -0
  10. data/lib/browserify-rails/browserify_processor.rb +109 -0
  11. data/lib/browserify-rails/railtie.rb +20 -0
  12. data/lib/browserify-rails/tasks/npm.rake +20 -0
  13. data/lib/browserify-rails/version.rb +3 -0
  14. data/test/browserify_processor_test.rb +46 -0
  15. data/test/compilation_test.rb +82 -0
  16. data/test/dummy/Rakefile +7 -0
  17. data/test/dummy/app/assets/javascripts/application.js.example +1 -0
  18. data/test/dummy/app/assets/javascripts/foo.js.example +2 -0
  19. data/test/dummy/app/assets/javascripts/nested/index.js.example +1 -0
  20. data/test/dummy/app/assets/stylesheets/application.css +7 -0
  21. data/test/dummy/app/controllers/application_controller.rb +3 -0
  22. data/test/dummy/app/controllers/home_controller.rb +5 -0
  23. data/test/dummy/app/helpers/application_helper.rb +2 -0
  24. data/test/dummy/app/helpers/home_helper.rb +2 -0
  25. data/test/dummy/app/mailers/.gitkeep +0 -0
  26. data/test/dummy/app/models/.gitkeep +0 -0
  27. data/test/dummy/app/views/home/index.html.erb +2 -0
  28. data/test/dummy/app/views/layouts/application.html.erb +15 -0
  29. data/test/dummy/config.ru +4 -0
  30. data/test/dummy/config/application.rb +44 -0
  31. data/test/dummy/config/boot.rb +10 -0
  32. data/test/dummy/config/database.yml +25 -0
  33. data/test/dummy/config/environment.rb +5 -0
  34. data/test/dummy/config/environments/development.rb +27 -0
  35. data/test/dummy/config/environments/production.rb +54 -0
  36. data/test/dummy/config/environments/test.rb +39 -0
  37. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  38. data/test/dummy/config/initializers/inflections.rb +10 -0
  39. data/test/dummy/config/initializers/mime_types.rb +5 -0
  40. data/test/dummy/config/initializers/secret_token.rb +7 -0
  41. data/test/dummy/config/initializers/session_store.rb +8 -0
  42. data/test/dummy/config/initializers/wrap_parameters.rb +12 -0
  43. data/test/dummy/config/locales/en.yml +5 -0
  44. data/test/dummy/config/routes.rb +60 -0
  45. data/test/dummy/package.json +12 -0
  46. data/test/dummy/public/404.html +26 -0
  47. data/test/dummy/public/422.html +26 -0
  48. data/test/dummy/public/500.html +26 -0
  49. data/test/dummy/public/favicon.ico +0 -0
  50. data/test/dummy/script/rails +6 -0
  51. data/test/fixtures/application.changed.out.js +12 -0
  52. data/test/fixtures/application.foo_changed.out.js +11 -0
  53. data/test/fixtures/application.out.js +11 -0
  54. data/test/fixtures/empty_module.js +2 -0
  55. data/test/fixtures/foo.out.js +9 -0
  56. data/test/test_helper.rb +20 -0
  57. metadata +151 -29
  58. data/.rspec +0 -2
  59. data/spec/browserify/rails_spec.rb +0 -11
  60. data/spec/spec_helper.rb +0 -2
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 907912f1aadcbeafc0c4d0a980f519e5c9ca1ba6
4
+ data.tar.gz: 81dfa83d15625dcbc59c3991dbfd040025213702
5
+ SHA512:
6
+ metadata.gz: be64aec51ab18d1fa128560901a749caff2044419755e38e9eb9092a433e8f63d47fe65f07f514bd31a2f8a826efb48ebab91407ca0e3bddf4b06fa4f8702b32
7
+ data.tar.gz: ecebfdc971e5617d74278a29dbdaf4d9cd761b5586d517a0cf5ad7faddcf9f79fa2b195ea3c3d4ed1f9fa9042033249cfd776df905f2bdba2980efd87ebc1dfb
data/.gitignore CHANGED
@@ -14,4 +14,13 @@ rdoc
14
14
  spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
+ test/dummy/data
18
+ test/dummy/db/*.sqlite3
19
+ test/dummy/log/*
20
+ test/dummy/node_modules
21
+ test/dummy/public/assets
22
+ test/dummy/public/system
23
+ test/dummy/db/schema.rb
17
24
  tmp
25
+ test/dummy/app/assets/javascripts/*.js
26
+ test/dummy/app/assets/javascripts/**/*.js
data/.travis.yml ADDED
@@ -0,0 +1 @@
1
+ language: ruby
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Aaron Rutkovsky
1
+ Copyright (c) 2013 Henry Hsu
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,29 +1,97 @@
1
- # Browserify::Rails
1
+ # browserify-rails
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/hsume2/browserify-rails.png?branch=master)](https://travis-ci.org/hsume2/browserify-rails)
4
4
 
5
- ## Installation
5
+ This library adds CommonJS module support to Sprockets (via Browserify).
6
+
7
+ It let's you mix and match `//= require` directives and `require()` calls for including plain javascript files as well as modules.
8
+
9
+ 1. Manage JS modules with `npm`
10
+ 2. Serve assets with Sprockets
11
+ 3. Require modules with `require()` (without separate `//= require` directives)
12
+ 4. Only build required modules
13
+ 5. Require *npm modules* in your Rails assets
14
+
15
+ ## Getting Started
6
16
 
7
17
  Add this line to your application's Gemfile:
8
18
 
9
- gem 'browserify-rails'
19
+ gem "hsume2-browserify-rails", "~> 0.2.0", :require => "browserify-rails"
20
+
21
+ Create `package.json` in your Rails root:
22
+
23
+ ```js
24
+ {
25
+ "name": "something",
26
+ "devDependencies" : {
27
+ "browserify": "~> 4.1"
28
+ },
29
+ "license": "MIT",
30
+ "engines": {
31
+ "node": ">= 0.10"
32
+ }
33
+ }
34
+ ```
35
+
36
+ Then run:
37
+
38
+ npm install
10
39
 
11
- And then execute:
40
+ Then start writing CommonJS, and everything will magically work!:
12
41
 
13
- $ bundle
42
+ ```js
43
+ // foo.js
44
+ module.exports = function (n) { return n * 11 }
14
45
 
15
- Or install it yourself as:
46
+ // application.js
47
+ var foo = require('./foo');
48
+ console.log(foo(12));
49
+ ```
16
50
 
17
- $ gem install browserify-rails
51
+ ## Coffeescript
18
52
 
19
- ## Usage
53
+ Coffeescript is handled seamlessly, if you name your files `*.js.coffee`. That
54
+ way the coffeescript compiler will already have done it's work, when we are
55
+ putting the javascript tools to work.
20
56
 
21
- TODO: Write usage instructions here
57
+ ## Configuration
58
+
59
+ You can configure different options of browserify-rails by adding one of lines
60
+ mentioned below into your `config/application.rb` or your environment file
61
+ (`config/environments/*.rb`):
62
+
63
+ ```ruby
64
+ class My::Application < Rails::Application
65
+ # Paths, that should be browserified. We browserify everything, that
66
+ # matches (===) one of the paths. So you will most likely put lambdas
67
+ # regexes in here.
68
+ #
69
+ # By default only files in /app and /node_modules are browserified,
70
+ # vendor stuff is normally not made for browserification and may stop
71
+ # working.
72
+ config.browserify_rails.paths << /vendor\/assets\/javascripts\/module.js/
73
+
74
+ # Environments, in which to generate source maps
75
+ #
76
+ # The default is `["development"]`.
77
+ config.browserify_rails.source_map_environments << "production"
78
+
79
+ # Command line options used when running browserify
80
+ #
81
+ # can be provided as an array:
82
+ config.browserify_rails.commandline_options = ["-t browserify-shim", "--fast"]
83
+
84
+ # or as a string:
85
+ config.browserify_rails.commandline_options = "-t browserify-shim --fast"
86
+ ```
22
87
 
23
88
  ## Contributing
24
89
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Add some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
90
+ Pull requests appreciated.
91
+
92
+ ## Contributors
93
+
94
+ * [Henry Hsu](https://github.com/hsume2)
95
+ * [Cássio Souza](https://github.com/cassiozen)
96
+ * [Marten Lienen](https://github.com/CQQL)
97
+ * [Lukasz Sagol](https://github.com/zgryw)
data/Rakefile CHANGED
@@ -1 +1,27 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = false
10
+ end
11
+
12
+ namespace :dummy do
13
+ namespace :npm do
14
+ desc "Run npm install for dummy app"
15
+ task :install do
16
+ dummy_dir = Bundler.root.join 'test/dummy'
17
+
18
+ sh "cd #{dummy_dir} && npm install" do |ok, res|
19
+ fail "Error running npm install in #{dummy_dir}." unless ok
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ task :test => ['dummy:npm:install']
26
+
27
+ task :default => :test
@@ -1,22 +1,27 @@
1
- # -*- encoding: utf-8 -*-
1
+ # coding: utf-8
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'browserify-rails/version'
4
5
 
5
- Gem::Specification.new do |gem|
6
- gem.name = "browserify-rails"
7
- gem.version = "0.0.1"
8
- gem.authors = ["Aaron Rutkovsky"]
9
- gem.email = ["aaron.rutkovsky@gmail.com"]
10
- gem.description = %q{Rails + Browserify}
11
- gem.summary = %q{summary}
12
- gem.homepage = ""
13
- gem.license = "MIT"
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "browserify-rails"
8
+ spec.version = BrowserifyRails::VERSION
9
+ spec.authors = ["Henry Hsu"]
10
+ spec.email = ["hhsu@zendesk.com"]
11
+ spec.description = %q{Browserify + Rails = CommonJS Heaven}
12
+ spec.summary = %q{Get the best of both worlds: Browserify + Rails = CommonJS Heaven}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
14
15
 
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
19
20
 
20
- gem.add_development_dependency "rake"
21
- gem.add_development_dependency "rspec"
21
+ spec.add_runtime_dependency "sprockets", "~> 2.0"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rails", "~> 3.2"
26
+ spec.add_development_dependency "mocha"
22
27
  end
@@ -1 +1,9 @@
1
+ require "sprockets"
1
2
 
3
+ require "browserify-rails/browserify_error"
4
+ require "browserify-rails/browserify_processor"
5
+ require "browserify-rails/railtie"
6
+ require "browserify-rails/version"
7
+
8
+ module BrowserifyRails
9
+ end
@@ -0,0 +1,5 @@
1
+ module BrowserifyRails
2
+ # Something went wrong while executing browserify
3
+ class BrowserifyError < RuntimeError
4
+ end
5
+ end
@@ -0,0 +1,109 @@
1
+ require "open3"
2
+ require "json"
3
+
4
+ module BrowserifyRails
5
+ class BrowserifyProcessor < Tilt::Template
6
+ BROWSERIFY_CMD = "./node_modules/.bin/browserify".freeze
7
+
8
+ def prepare
9
+ end
10
+
11
+ def evaluate(context, locals, &block)
12
+ if should_browserify? && commonjs_module?
13
+ asset_dependencies(context.environment.paths).each do |path|
14
+ context.depend_on(path)
15
+ end
16
+
17
+ browserify
18
+ else
19
+ data
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def should_browserify?
26
+ Rails.application.config.browserify_rails.paths.any? do |path_spec|
27
+ path_spec === file
28
+ end
29
+ end
30
+
31
+ # Is this a commonjs module?
32
+ #
33
+ # Be here as strict as possible, so that non-commonjs files are not
34
+ # preprocessed.
35
+ def commonjs_module?
36
+ data.to_s.include?("module.exports") || dependencies.length > 0
37
+ end
38
+
39
+ # This primarily filters out required files from node modules
40
+ #
41
+ # @return [<String>] Paths of dependencies, that are in asset directories
42
+ def asset_dependencies(asset_paths)
43
+ dependencies.select do |path|
44
+ path.start_with?(*asset_paths)
45
+ end
46
+ end
47
+
48
+ # @return [<String>] Paths of files, that this file depends on
49
+ def dependencies
50
+ @dependencies ||= run_browserify("--list").lines.map(&:strip).select do |path|
51
+ # Filter the temp file, where browserify caches the input stream
52
+ File.exists?(path)
53
+ end
54
+ end
55
+
56
+ def browserify
57
+ run_browserify(options)
58
+ end
59
+
60
+ def browserify_cmd
61
+ cmd = File.join(Rails.root, BROWSERIFY_CMD)
62
+
63
+ if !File.exist?(cmd)
64
+ raise BrowserifyRails::BrowserifyError.new("browserify could not be found at #{cmd}. Please run npm install.")
65
+ end
66
+
67
+ cmd
68
+ end
69
+
70
+ # Run browserify with `data` on standard input.
71
+ #
72
+ # We are passing the data via stdin, so that earlier preprocessing steps are
73
+ # respected. If you had, say, an "application.js.coffee.erb", passing the
74
+ # filename would fail, because browserify would read the original file with
75
+ # ERB tags and fail. By passing the data via stdin, we get the expected
76
+ # behavior of success, because everything has been compiled to plain
77
+ # javascript at the time this processor is called.
78
+ #
79
+ # @raise [BrowserifyRails::BrowserifyError] if browserify does not succeed
80
+ # @param options [String] Options for browserify
81
+ # @return [String] Output on standard out
82
+ def run_browserify(options)
83
+ # The dash tells browserify to read from STDIN
84
+ command = "#{browserify_cmd} #{options} -"
85
+ directory = File.dirname(file)
86
+ stdout, stderr, status = Open3.capture3(command, stdin_data: data, chdir: directory)
87
+
88
+ if !status.success?
89
+ raise BrowserifyRails::BrowserifyError.new("Error while running `#{command}`:\n\n#{stderr}")
90
+ end
91
+
92
+ stdout
93
+ end
94
+
95
+ def options
96
+ options = []
97
+
98
+ options.push("-d") if config.source_map_environments.include?(Rails.env)
99
+
100
+ options += Array(config.commandline_options) if config.commandline_options.present?
101
+
102
+ options.uniq.join(" ")
103
+ end
104
+
105
+ def config
106
+ BrowserifyRails::Railtie.config.browserify_rails
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,20 @@
1
+ module BrowserifyRails
2
+ class Railtie < Rails::Engine
3
+ config.browserify_rails = ActiveSupport::OrderedOptions.new
4
+
5
+ # Which paths should be browserified?
6
+ config.browserify_rails.paths = [lambda { |p| p.start_with?(Rails.root.join("app").to_s) },
7
+ lambda { |p| p.start_with?(Rails.root.join("node_modules").to_s) }]
8
+
9
+ # Environments to generate source maps in
10
+ config.browserify_rails.source_map_environments = ["development"]
11
+
12
+ initializer :setup_browserify do |app|
13
+ app.assets.register_postprocessor "application/javascript", BrowserifyRails::BrowserifyProcessor
14
+ end
15
+
16
+ rake_tasks do
17
+ Dir[File.join(File.dirname(__FILE__), "tasks/*.rake")].each { |f| load f }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ namespace :npm do
2
+ desc "Run npm install"
3
+ task :install do
4
+ sh "npm install" do |ok, res|
5
+ fail "Error running npm install." unless ok
6
+ end
7
+ end
8
+
9
+ desc "Clean npm node_modules"
10
+ task :clean do
11
+ sh "rm -rf ./node_modules" do |ok, res|
12
+ fail "Error cleaning npm node_modules." unless ok
13
+ end
14
+ end
15
+
16
+ namespace :install do
17
+ desc "Run a clean npm install"
18
+ task :clean => ['npm:clean', 'npm:install']
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module BrowserifyRails
2
+ VERSION = "0.3.0"
3
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+
3
+ class BrowserifyProcessorTest < ActiveSupport::TestCase
4
+ setup do
5
+ @empty_module = fixture("empty_module.js")
6
+ @processor = BrowserifyRails::BrowserifyProcessor.new { |p| @empty_module }
7
+ end
8
+
9
+ test "should run command without options if none provided" do
10
+ stub_engine_config :commandline_options, nil
11
+ assert_equal "", @processor.send(:options)
12
+ end
13
+
14
+ test "should run command without options if empty array provided" do
15
+ stub_engine_config :commandline_options, []
16
+ assert_equal "", @processor.send(:options)
17
+ end
18
+
19
+ test "should convert options provided as an array to string" do
20
+ stub_engine_config :commandline_options, ["-d", "-i test1.js"]
21
+ assert_equal "-d -i test1.js", @processor.send(:options)
22
+ end
23
+
24
+ test "should allow providing options as a string" do
25
+ stub_engine_config :commandline_options, "-d -i test2.js"
26
+
27
+ assert_equal "-d -i test2.js", @processor.send(:options)
28
+ end
29
+
30
+ test "should remove duplicate options when provided as an array" do
31
+ stub_engine_config :commandline_options, ["-d", "-i test3.js", "-d"]
32
+
33
+ assert_equal "-d -i test3.js", @processor.send(:options)
34
+ end
35
+
36
+ test "should add -d option if current env is in source_maps_env list" do
37
+ stub_engine_config :commandline_options, ["-i test4.js"]
38
+ stub_engine_config :source_map_environments, [Rails.env]
39
+
40
+ assert_equal "-d -i test4.js", @processor.send(:options)
41
+ end
42
+
43
+ def stub_engine_config(key, value)
44
+ @processor.send(:config).stubs(key).returns(value)
45
+ end
46
+ end