├── .gitignore ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── lib ├── rails-vue-loader.rb └── sprockets │ └── vue │ ├── script.rb │ ├── style.rb │ ├── utils.rb │ └── version.rb ├── rails-vue-loader.gemspec └── test ├── fixtures ├── components │ ├── card.style.vue │ ├── card.tpl.vue │ └── card.vue └── index.vue └── test_vue.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.rbc 2 | .bundle 3 | *.gem 4 | Gemfile.lock 5 | README.html 6 | doc 7 | docs 8 | pkg 9 | tmp 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Kikyous 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rails-vue-loader 2 | 3 | [![Gem](https://img.shields.io/gem/v/rails-vue-loader.svg)](https://rubygems.org/gems/rails-vue-loader) 4 | [![Gem](https://img.shields.io/gem/dt/rails-vue-loader.svg)](https://rubygems.org/gems/rails-vue-loader) 5 | 6 | rails-vue-loader(formerly sprockets-vue) -- a [Sprockets](https://github.com/rails/sprockets) transformer that converts .vue file into js object. 7 | 8 | # feature 9 | 10 | following tag is supported in .vue file 11 | * script (coffeescript and js) 12 | * template (currently html only) 13 | * style (scss, sass and css) 14 | 15 | # install 16 | add `gem 'rails-vue-loader'` to Gemfile, and run bundle, currently works with sprockets 3. 17 | 18 | # example 19 | 20 | * app/assets/javascripts/application.coffee 21 | 22 | ```coffee 23 | #= require index 24 | 25 | new Vue( 26 | el: '#search', 27 | components: { 28 | 'index': VComponents.index 29 | } 30 | ) 31 | ``` 32 | 33 | * app/assets/javascripts/index.vue *(stored into VComponents.index when required)* 34 | ```vue 35 | //= require components/card 36 | 48 | 49 | 59 | 60 | 67 | ``` 68 | 69 | * application.scss 70 | ```scss 71 | //=require index 72 | ``` 73 | 74 | > you can include .vue file in css file, it's style block will be automatic processed. 75 | you can also use `require_tree` to include all .vue file.😘 76 | `scoped` will not be supported. 77 | 78 | # advanced 79 | * [multi file component](https://github.com/kikyous/sprockets-vue/wiki/multi-file-component) 80 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rake/testtask' 2 | 3 | task :default => :test 4 | 5 | Rake::TestTask.new do |t| 6 | t.libs << 'test' 7 | t.warning = true 8 | end 9 | -------------------------------------------------------------------------------- /lib/rails-vue-loader.rb: -------------------------------------------------------------------------------- 1 | require 'sprockets' 2 | require 'sprockets/vue/version' 3 | require 'sprockets/vue/utils' 4 | require 'sprockets/vue/script' 5 | require 'sprockets/vue/style' 6 | module Sprockets 7 | if respond_to?(:register_transformer) 8 | register_mime_type 'text/vue', extensions: ['.vue'], charset: :unicode 9 | register_transformer 'text/vue', 'application/javascript', Vue::Script 10 | register_transformer 'text/vue', 'text/css', Vue::Style 11 | 12 | register_processor 'text/vue', Sprockets::DirectiveProcessor 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/sprockets/vue/script.rb: -------------------------------------------------------------------------------- 1 | require 'active_support/concern' 2 | require "action_view" 3 | module Sprockets::Vue 4 | class Script 5 | class << self 6 | include ActionView::Helpers::JavaScriptHelper 7 | 8 | SCRIPT_REGEX = Utils.node_regex('script') 9 | TEMPLATE_REGEX = Utils.node_regex('template') 10 | SCRIPT_COMPILES = { 11 | 'coffee' => ->(s, input){ 12 | CoffeeScript.compile(s, sourceMap: true, sourceFiles: [input[:source_path]], no_wrap: true) 13 | }, 14 | 'es6' => ->(s, input){ 15 | Babel::Transpiler.transform(data, {}) #TODO 16 | }, 17 | nil => ->(s,input){ { 'js' => s } } 18 | } 19 | def call(input) 20 | data = input[:data] 21 | name = input[:name] 22 | input[:cache].fetch([cache_key, input[:source_path], data]) do 23 | script = SCRIPT_REGEX.match(data) 24 | template = TEMPLATE_REGEX.match(data) 25 | output = [] 26 | map = nil 27 | if script 28 | result = SCRIPT_COMPILES[script[:lang]].call(script[:content], input) 29 | 30 | map = result['sourceMap'] 31 | 32 | output << "'object' != typeof VComponents && (this.VComponents = {}); 33 | var module = { exports: null }; 34 | #{result['js']}; VComponents['#{name}'] = module.exports;" 35 | end 36 | 37 | if template 38 | output << "VComponents['#{name.sub(/\.tpl$/, "")}'].template = '#{j template[:content]}';" 39 | end 40 | 41 | { data: "#{warp(output.join)}", map: map } 42 | end 43 | end 44 | 45 | def warp(s) 46 | "(function(){#{s}}).call(this);" 47 | end 48 | 49 | def cache_key 50 | [ 51 | self.name, 52 | VERSION, 53 | ].freeze 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/sprockets/vue/style.rb: -------------------------------------------------------------------------------- 1 | module Sprockets::Vue 2 | class Style 3 | class << self 4 | STYLE_REGEX = Utils.node_regex('style') 5 | STYLE_COMPILES = { 6 | 'scss' => Sprockets::ScssProcessor, 7 | 'sass' => Sprockets::SassProcessor, 8 | nil => ->(i){i[:data]} 9 | } 10 | def call(input) 11 | data = input[:data] 12 | input[:cache].fetch([cache_key, input[:filename], data]) do 13 | style = STYLE_REGEX.match(data) 14 | if style 15 | input[:data] = style[:content] 16 | STYLE_COMPILES[style[:lang]].call(input) 17 | else 18 | '' 19 | end 20 | end 21 | end 22 | 23 | def cache_key 24 | [ 25 | self.name, 26 | VERSION, 27 | ].freeze 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/sprockets/vue/utils.rb: -------------------------------------------------------------------------------- 1 | module Sprockets::Vue::Utils 2 | class << self 3 | def node_regex(tag) 4 | %r( 5 | \<#{tag} 6 | (\s+lang=["'](?\w+)["'])? 7 | \> 8 | (?.+) 9 | \<\/#{tag}\> 10 | )mx 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/sprockets/vue/version.rb: -------------------------------------------------------------------------------- 1 | module Sprockets 2 | module Vue 3 | VERSION = '0.1.1' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /rails-vue-loader.gemspec: -------------------------------------------------------------------------------- 1 | $:.unshift File.expand_path("../lib", __FILE__) 2 | require 'sprockets/vue/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'rails-vue-loader' 6 | s.version = Sprockets::Vue::VERSION 7 | 8 | s.homepage = "https://github.com/kikyous/rails-vue-loader" 9 | s.summary = "Sprockets Vue transformer" 10 | s.description = <<-EOS 11 | A Sprockets transformer that converts .vue file into js object. 12 | EOS 13 | s.license = "MIT" 14 | 15 | s.files = Dir["README.md", "MIT-LICENSE", "lib/**/*.rb"] 16 | 17 | s.add_dependency 'sprockets', '>= 3.0.0' 18 | s.add_dependency 'actionview' 19 | s.add_dependency 'activesupport' 20 | s.add_development_dependency 'rake' 21 | s.add_development_dependency 'minitest' 22 | s.add_development_dependency 'execjs' 23 | s.add_development_dependency 'pry' 24 | s.add_development_dependency 'sass' 25 | s.add_development_dependency 'coffee-script' 26 | 27 | s.authors = ['kikyous'] 28 | s.email = 'kikyous@163.com' 29 | end 30 | -------------------------------------------------------------------------------- /test/fixtures/components/card.style.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /test/fixtures/components/card.tpl.vue: -------------------------------------------------------------------------------- 1 | 27 | -------------------------------------------------------------------------------- /test/fixtures/components/card.vue: -------------------------------------------------------------------------------- 1 | //= require_self 2 | //= require ./card.tpl 3 | //= require ./card.style 4 | 17 | -------------------------------------------------------------------------------- /test/fixtures/index.vue: -------------------------------------------------------------------------------- 1 | //= require components/card 2 | 14 | 15 | 25 | 26 | 33 | -------------------------------------------------------------------------------- /test/test_vue.rb: -------------------------------------------------------------------------------- 1 | require 'minitest/autorun' 2 | require 'sprockets' 3 | require 'sprockets/vue' 4 | require 'execjs' 5 | require "coffee-script" 6 | require 'sass' 7 | require 'pry' 8 | 9 | class TestVue < MiniTest::Test 10 | def setup 11 | @env = Sprockets::Environment.new 12 | @env.append_path File.expand_path("../fixtures", __FILE__) 13 | end 14 | 15 | def test_directive 16 | assert asset = @env["index"] 17 | assert asset.metadata[:required].length, 1 18 | end 19 | 20 | def test_mimetype 21 | assert asset = @env["index"] 22 | assert_equal 'text/vue', asset.content_type 23 | end 24 | 25 | def test_script_transformer 26 | asset = @env['index.js'].to_s 27 | context = ExecJS.compile(asset) 28 | 29 | assert_equal context.eval("VComponents.index.data().search"), 'test' 30 | components = context.eval("VComponents", bare: true) 31 | assert_equal components.keys, ["components/card", "index"] 32 | assert components['index']['template'].match(/clear-icon glyphicon glyphicon-remove/) 33 | assert components['components/card']['template'].match(/@click='expand=!expand'/) 34 | end 35 | 36 | def test_style_transformer 37 | asset = @env['index.css'].to_s 38 | assert asset.match(/.search .icon-input/) 39 | assert asset.match(/.avatar/) 40 | end 41 | end 42 | --------------------------------------------------------------------------------