vueport 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +7 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/example/Procfile +2 -0
- data/example/Procfile.dev +2 -0
- data/example/application.js +5 -0
- data/example/babelrc +3 -0
- data/example/index.js +35 -0
- data/example/server.js +10 -0
- data/example/setup.js +14 -0
- data/example/webpack.server.js +59 -0
- data/lib/generators/vueport/install_generator.rb +166 -0
- data/lib/tasks/vueport.rake +24 -0
- data/lib/vueport.rb +25 -0
- data/lib/vueport/helper.rb +8 -0
- data/lib/vueport/node_client.rb +40 -0
- data/lib/vueport/railtie.rb +22 -0
- data/lib/vueport/renderer.rb +42 -0
- data/lib/vueport/version.rb +3 -0
- data/vueport.gemspec +33 -0
- metadata +185 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 45dc87f34b0a0b04c7de4f4754b968397e6a3cfa
|
4
|
+
data.tar.gz: 7b1e46d1c085bf4679c7db3c0c4fe7751d0b6bc8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fdd177551b9f4b464ce3ac8076e8187fb9bf8a6494698f3b639f987cec6f2c6cc99af1930f6bb39c9063cfdda40300099cc4059a34e3c45a6ad0c4d488cea1af
|
7
|
+
data.tar.gz: 1463e24bf2e439afb5aab46a9ea47f450f4ef760e5ae04f078175f71ff973eef9f757fa397c4a86b95498f720183ea8828dd900806792d4d97b4195e503cb96f
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at samtgarson@gmail.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Sam Garson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# Vueport
|
2
|
+
>Single file components and SSR for Rails with Vue JS and Webpack
|
3
|
+
|
4
|
+
[](https://circleci.com/gh/samtgarson/vueport) [](https://rubygems.org/gems/vueport) [](https://rubygems.org/gems/vueport)
|
5
|
+
|
6
|
+
Vueport provides your Rails app with a modern, componentized approach to UI development by using Webpack and Vue.js to enable single file, reactive components rendered on the server and the client and seamless integration with your Rails views.
|
7
|
+
|
8
|
+
Take a look at the Vue.js [documentation on single file components](https://vuejs.org/guide/single-file-components.html) for more information on that side of things.
|
9
|
+
|
10
|
+
Vueport piggybacks onto the [WebpackRails gem](https://github.com/mipearson/webpack-rails) to get Webpack setup with Rails, so check that out for more information.
|
11
|
+
|
12
|
+
## Example Rails App
|
13
|
+
|
14
|
+
[Here](https://github.com/samtgarson/vueport-example).
|
15
|
+
|
16
|
+
## Installation
|
17
|
+
|
18
|
+
Add this line to your application's Gemfile:
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'vueport'
|
22
|
+
```
|
23
|
+
|
24
|
+
And then execute:
|
25
|
+
|
26
|
+
$ bundle
|
27
|
+
|
28
|
+
Or install it yourself as:
|
29
|
+
|
30
|
+
$ gem install vueport
|
31
|
+
|
32
|
+
Then just run
|
33
|
+
|
34
|
+
```shell
|
35
|
+
rails generate vueport:install
|
36
|
+
```
|
37
|
+
|
38
|
+
to bootstrap everything you need to get started (this will install WebpackRails and also everything Vueport needs on top).
|
39
|
+
|
40
|
+
To run your app, execute
|
41
|
+
|
42
|
+
```shell
|
43
|
+
bundle exec foreman start -f Procfile.dev
|
44
|
+
```
|
45
|
+
|
46
|
+
to boot the Webpack Dev server and your Rails app!
|
47
|
+
|
48
|
+
## Production Deployment
|
49
|
+
|
50
|
+
Ensure to run `rails vueport:compile` as part of your deployment process to production. This compiles the production version of your client side bundle, as well as compiling the server side bundle for our Node JS app to use.
|
51
|
+
|
52
|
+
In production we send HTTP requests to a basic NodeJS server to render our content. To run the Rails app and the Node server concurrently, use `Procfile`.
|
53
|
+
|
54
|
+
## Usage
|
55
|
+
|
56
|
+
### View Helper
|
57
|
+
|
58
|
+
Wrap your application in the `vueport` helper, to render out your components. E.g. in your `application.html.erb`:
|
59
|
+
|
60
|
+
```erb
|
61
|
+
<body>
|
62
|
+
<%= vueport do %>
|
63
|
+
<%= render partial: 'shared/nav' %>
|
64
|
+
<%= yield %>
|
65
|
+
<% end %>
|
66
|
+
</body>
|
67
|
+
```
|
68
|
+
|
69
|
+
It can also accept a single argument. E.g.:
|
70
|
+
|
71
|
+
```erb
|
72
|
+
<body>
|
73
|
+
<%= vueport yield %>
|
74
|
+
</body>
|
75
|
+
```
|
76
|
+
|
77
|
+
### Asset Setup
|
78
|
+
|
79
|
+
Add the Webpack Rails helpers to your layout to include your Javascript and CSS (see the [WebpackRails readme](https://github.com/mipearson/webpack-rails) for more information).
|
80
|
+
|
81
|
+
**Ensure you place the JS entrypoint after the Vueport helper!**
|
82
|
+
|
83
|
+
E.g.:
|
84
|
+
|
85
|
+
```erb
|
86
|
+
<head>
|
87
|
+
<%= stylesheet_link_tag *webpack_asset_paths('application', extension: 'css') %>
|
88
|
+
</head>
|
89
|
+
<body>
|
90
|
+
<%= vueport do %>
|
91
|
+
<%= render partial: 'shared/nav' %>
|
92
|
+
<%= yield %>
|
93
|
+
<% end %>
|
94
|
+
|
95
|
+
<%= javascript_include_tag *webpack_asset_paths("application", extension: 'js') %>
|
96
|
+
</body>
|
97
|
+
```
|
98
|
+
|
99
|
+
### Default config
|
100
|
+
|
101
|
+
Out of the box, Vueport expects your components to live in _app/components_, and compiles assets to _public/webpack_. To change these, you'll need to change both the Webpack config (in _config/webpack.config.js_ and _config/webpack.server.js_) and the Vue gem application config. To do this, in an initializer do:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
Vueport.configure do |config|
|
105
|
+
config[:server_port] = 3001
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
_Check out the WebpackRails gem for information on its configuration._
|
110
|
+
|
111
|
+
## How does it work?
|
112
|
+
|
113
|
+
To see how WebpackRails works, take a look at [this section of the readme](https://github.com/mipearson/webpack-rails#how-it-works).
|
114
|
+
|
115
|
+
Vueport extends the functionality of WebpackRails by adding a few extra features:
|
116
|
+
|
117
|
+
- Webpack setup to read and compile Vue components
|
118
|
+
- Webpack setup to enable HMR (Hot Module Reloading) for an A+ development experience
|
119
|
+
- Server Side rendering in production.
|
120
|
+
|
121
|
+
### Server Side Rendering (SSR)
|
122
|
+
|
123
|
+
To enable Server Side rendering, I created a simple NodeJS app which uses the [Vue Server Renderer](https://www.npmjs.com/package/vue-server-renderer) to render out the contents of the page on each request. To enable Client Side rehydration, we also attach the original view contents in a template for the Client Side Vue instance to pick up.
|
124
|
+
|
125
|
+
SSR is only enabled in production.
|
126
|
+
|
127
|
+
## Why Vue.js?
|
128
|
+
|
129
|
+
My experience of working with many modern UI libraries, and particulary with integrating them with Rails apps (especially React and Vue JS), has lead me to the conclusion that Vue JS seems to be a more explcit and 'batteries included' library when building compnents for Rails.
|
130
|
+
|
131
|
+
I use React on a regular basis for SPAs and love its functional philosophy, but for writing components to fit into a Rails frontend, Vue seems to provide me with the least complexity, and seems to be easiest for Ruby developers to reason about.
|
132
|
+
|
133
|
+
For a Vue.js and React [collaborative](https://github.com/vuejs/vuejs.org/issues/364) comparison, [check this out](https://vuejs.org/guide/comparison.html).
|
134
|
+
|
135
|
+
## To Do
|
136
|
+
|
137
|
+
- [x] Handle SSR
|
138
|
+
- [ ] Make webpack config more like the config from the [Vue CLI template](https://github.com/vuejs-templates/webpack/tree/master/template/build)
|
139
|
+
- [ ] Optimize SSR interaction with NodeJS
|
140
|
+
- [ ] JS Component test setup
|
141
|
+
|
142
|
+
## Development
|
143
|
+
|
144
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
145
|
+
|
146
|
+
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).
|
147
|
+
|
148
|
+
## Contributing
|
149
|
+
|
150
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/samtgarson/vueport. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
151
|
+
|
152
|
+
## Thanks
|
153
|
+
|
154
|
+
- Many thanks to [Evan You](https://github.com/yyx990803) and the VueJS for sustaining such a vibrant and supporting community around Vue JS
|
155
|
+
- Many thanks also to [mipearson](https://github.com/mipearson) for his WebpackRails gem which this gem completely cannibalizes
|
156
|
+
|
157
|
+
## License
|
158
|
+
|
159
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
160
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "vueport"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/example/Procfile
ADDED
data/example/babelrc
ADDED
data/example/index.js
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
const app = require('express')()
|
2
|
+
const fs = require('fs');
|
3
|
+
const path = require('path');
|
4
|
+
const bodyParser = require('body-parser')
|
5
|
+
const vueServerRenderer = require('vue-server-renderer');
|
6
|
+
const morgan = require('morgan')
|
7
|
+
|
8
|
+
const filePath = path.join(__dirname, './public/webpack/bundle.server.js')
|
9
|
+
const code = fs.readFileSync(filePath, 'utf8');
|
10
|
+
const bundleRenderer = vueServerRenderer.createBundleRenderer(code);
|
11
|
+
|
12
|
+
const PORT = process.env['PORT'] || 5000
|
13
|
+
|
14
|
+
app.use(bodyParser.text())
|
15
|
+
app.use(morgan('tiny'))
|
16
|
+
|
17
|
+
const render = html => {
|
18
|
+
return p = new Promise((resolve, reject) => {
|
19
|
+
bundleRenderer.renderToString({body: html}, (err, html) => {
|
20
|
+
if (err) return reject(err)
|
21
|
+
else return resolve(html)
|
22
|
+
})
|
23
|
+
})
|
24
|
+
}
|
25
|
+
|
26
|
+
app.post('/render', (req, res) => {
|
27
|
+
render(req.body)
|
28
|
+
.catch(err => {
|
29
|
+
console.error(err)
|
30
|
+
res.status(500).send(JSON.stringify(err))
|
31
|
+
})
|
32
|
+
.then(html => res.send(html))
|
33
|
+
})
|
34
|
+
|
35
|
+
app.listen(PORT, () => console.log('listening on', PORT))
|
data/example/server.js
ADDED
data/example/setup.js
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
import Vue from 'vue'
|
2
|
+
// Import your components here, then include it in your Vue application below.
|
3
|
+
// (We've added /app to our webpack resolves for convenience)
|
4
|
+
|
5
|
+
// import MyComponent from 'components/my-component'
|
6
|
+
|
7
|
+
export default function (template) {
|
8
|
+
return new Vue({
|
9
|
+
template: template,
|
10
|
+
components: {
|
11
|
+
//MyComponent
|
12
|
+
}
|
13
|
+
})
|
14
|
+
}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
// Example webpack configuration with asset fingerprinting in production.
|
2
|
+
'use strict';
|
3
|
+
|
4
|
+
var path = require('path');
|
5
|
+
var webpack = require('webpack');
|
6
|
+
|
7
|
+
var config = {
|
8
|
+
target: 'node', // !different
|
9
|
+
entry: './webpack/server.js',
|
10
|
+
output: {
|
11
|
+
libraryTarget: 'commonjs2', // !different
|
12
|
+
path: path.join(__dirname, '..', 'public', 'webpack'),
|
13
|
+
publicPath: '/webpack/',
|
14
|
+
filename: 'bundle.server.js',
|
15
|
+
},
|
16
|
+
resolve: {
|
17
|
+
root: path.join(__dirname, '..', 'webpack'),
|
18
|
+
extensions: ['', '.js', '.vue'],
|
19
|
+
fallback: [path.join(__dirname, '../node_modules'), path.join(__dirname, '../app/')]
|
20
|
+
},
|
21
|
+
|
22
|
+
plugins: [
|
23
|
+
new webpack.NoErrorsPlugin(),
|
24
|
+
new webpack.optimize.UglifyJsPlugin({
|
25
|
+
compressor: { warnings: false },
|
26
|
+
sourceMap: false
|
27
|
+
}),
|
28
|
+
new webpack.DefinePlugin({
|
29
|
+
'process.env': { NODE_ENV: JSON.stringify('production') }
|
30
|
+
}),
|
31
|
+
new webpack.optimize.DedupePlugin(),
|
32
|
+
new webpack.optimize.OccurenceOrderPlugin()
|
33
|
+
],
|
34
|
+
|
35
|
+
module: {
|
36
|
+
loaders: [
|
37
|
+
{
|
38
|
+
test: /\.vue$/,
|
39
|
+
loader: 'vue'
|
40
|
+
},
|
41
|
+
{
|
42
|
+
test: /\.json$/,
|
43
|
+
loader: 'json'
|
44
|
+
},
|
45
|
+
{
|
46
|
+
loaders: ['babel'],
|
47
|
+
test: /\.js$/,
|
48
|
+
exclude: /node_modules/
|
49
|
+
},
|
50
|
+
{
|
51
|
+
test: /\.(sc|sa|c)ss$/,
|
52
|
+
loaders: ['style', 'css', 'sass']
|
53
|
+
}
|
54
|
+
]
|
55
|
+
}
|
56
|
+
};
|
57
|
+
|
58
|
+
|
59
|
+
module.exports = config;
|
@@ -0,0 +1,166 @@
|
|
1
|
+
module Vueport
|
2
|
+
class InstallGenerator < ::Rails::Generators::Base
|
3
|
+
source_root File.expand_path('../../../../example', __FILE__)
|
4
|
+
desc 'Install extras for using Vue with WebpackRails'
|
5
|
+
|
6
|
+
def add_webpack_rails
|
7
|
+
gem 'webpack-rails'
|
8
|
+
end
|
9
|
+
|
10
|
+
def bundle_and_install_webpack
|
11
|
+
run 'gem install webpack-rails'
|
12
|
+
generate 'webpack_rails:install'
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_to_gitignore
|
16
|
+
append_to_file '.gitignore' do
|
17
|
+
<<-EOF.strip_heredoc
|
18
|
+
npm-debug.log
|
19
|
+
EOF
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def insert_resolve
|
24
|
+
inject_into_file 'config/webpack.config.js', after: "root: path.join(__dirname, '..', 'webpack')" do
|
25
|
+
<<~HEREDOC
|
26
|
+
,
|
27
|
+
extensions: ['', '.js', '.vue'],
|
28
|
+
fallback: [path.join(__dirname, '../node_modules'), path.join(__dirname, '../app/'),],
|
29
|
+
alias: {
|
30
|
+
// Use the standalone build to compile our page at runtime
|
31
|
+
'vue$': 'vue/dist/vue.common.js'
|
32
|
+
}
|
33
|
+
HEREDOC
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def insert_module
|
38
|
+
inject_into_file 'config/webpack.config.js', after: "assets: true\n })]" do
|
39
|
+
<<~HEREDOC
|
40
|
+
,
|
41
|
+
// Use the necessary loaders to process our components
|
42
|
+
module: {
|
43
|
+
loaders: [
|
44
|
+
{
|
45
|
+
test: /\.vue$/,
|
46
|
+
loader: 'vue'
|
47
|
+
},
|
48
|
+
{
|
49
|
+
loaders: ['babel'],
|
50
|
+
test: /\.js$/,
|
51
|
+
exclude: /node_modules/
|
52
|
+
},
|
53
|
+
{
|
54
|
+
test: /\.css$/,
|
55
|
+
loader: production ? ExtractTextPlugin.extract('vue-style', 'css') : 'style!css',
|
56
|
+
fallbackLoader: 'vue-style-loader'
|
57
|
+
}
|
58
|
+
]
|
59
|
+
},
|
60
|
+
vue: {
|
61
|
+
loaders: {
|
62
|
+
css: production ? ExtractTextPlugin.extract('vue-style', "css") : 'style!css'
|
63
|
+
}
|
64
|
+
}
|
65
|
+
HEREDOC
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def update_procfile
|
70
|
+
remove_file 'Procfile'
|
71
|
+
copy_file 'Procfile.dev', 'Procfile.dev'
|
72
|
+
copy_file 'Procfile', 'Procfile'
|
73
|
+
end
|
74
|
+
|
75
|
+
def insert_css_extract
|
76
|
+
inject_into_file 'config/webpack.config.js', after: "var StatsPlugin = require('stats-webpack-plugin');" do
|
77
|
+
<<~HEREDOC
|
78
|
+
|
79
|
+
var ExtractTextPlugin = require("extract-text-webpack-plugin");
|
80
|
+
HEREDOC
|
81
|
+
end
|
82
|
+
|
83
|
+
inject_into_file 'config/webpack.config.js', after: 'new webpack.optimize.OccurenceOrderPlugin()' do
|
84
|
+
<<~HEREDOC
|
85
|
+
,
|
86
|
+
new ExtractTextPlugin('[name]-[chunkhash].css')
|
87
|
+
HEREDOC
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_dev_tool
|
92
|
+
gsub_file 'config/webpack.config.js', 'cheap-module-eval-source-map', '#eval-source-map'
|
93
|
+
end
|
94
|
+
|
95
|
+
def create_server_config
|
96
|
+
copy_file 'webpack.server.js', 'config/webpack.server.js'
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_setup_files
|
100
|
+
remove_file 'webpack/application.js'
|
101
|
+
copy_file 'application.js', 'webpack/application.js'
|
102
|
+
copy_file 'setup.js', 'webpack/setup.js'
|
103
|
+
copy_file 'server.js', 'webpack/server.js'
|
104
|
+
copy_file 'index.js', 'index.js'
|
105
|
+
copy_file 'babelrc', '.babelrc'
|
106
|
+
empty_directory 'app/components'
|
107
|
+
end
|
108
|
+
|
109
|
+
def add_npm_scripts
|
110
|
+
inject_into_file 'package.json', before: '"dependencies": {' do
|
111
|
+
<<~HEREDOC
|
112
|
+
"scripts": {
|
113
|
+
"dev-server": "./node_modules/.bin/webpack-dev-server --hot --inline --config config/webpack.config.js --host 0.0.0.0",
|
114
|
+
"start": "NODE_ENV=production node ."
|
115
|
+
},
|
116
|
+
|
117
|
+
HEREDOC
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_npm_dependencies
|
122
|
+
inject_into_file 'package.json', after: '"webpack-dev-server": "^1.9.0"' do
|
123
|
+
<<~HEREDOC
|
124
|
+
,
|
125
|
+
"body-parser": "^1.15.2",
|
126
|
+
"express": "^4.14.0",
|
127
|
+
"morgan": "^1.7.0",
|
128
|
+
"extract-text-webpack-plugin": "^1.0.1",
|
129
|
+
"vue": "^2.1.3",
|
130
|
+
"vue-server-renderer": "^2.1.3",
|
131
|
+
"babel-core": "^6.17.0",
|
132
|
+
"babel-loader": "^6.2.5",
|
133
|
+
"babel-polyfill": "^6.16.0",
|
134
|
+
"babel-preset-es2015": "^6.16.0",
|
135
|
+
"babel-preset-stage-0": "^6.16.0",
|
136
|
+
"css-loader": "^0.25.0",
|
137
|
+
"style-loader": "^0.13.1",
|
138
|
+
"vue-loader": "^10.0.1",
|
139
|
+
"vue-style-loader": "^1.0.0",
|
140
|
+
"vue-template-compiler": "^2.1.3"
|
141
|
+
HEREDOC
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def run_npm_install
|
146
|
+
run 'npm install' if yes?("Would you like me to run 'npm install' for you (I've added a few things since last time?) [y/N]")
|
147
|
+
end
|
148
|
+
|
149
|
+
def whats_next
|
150
|
+
# rubocop:disable Rails/Output
|
151
|
+
puts <<-EOF.strip_heredoc
|
152
|
+
|
153
|
+
I've added a few things here and there to set you up using Vue in your Rails app.
|
154
|
+
|
155
|
+
Now you're already to create your first Vue component in app/components.
|
156
|
+
Run 'foreman start' to run the webpack-dev-server and rails server.
|
157
|
+
|
158
|
+
See the README.md for this gem at
|
159
|
+
https://github.com/samtgarson/vueport
|
160
|
+
for more info.
|
161
|
+
Thanks for using Vueport!
|
162
|
+
EOF
|
163
|
+
# rubocop:enable Rails/Output
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
namespace :vueport do
|
2
|
+
desc 'Compile client and server bundles'
|
3
|
+
task compile: :environment do
|
4
|
+
ENV['NODE_ENV'] = 'production'
|
5
|
+
webpack_bin = ::Rails.root.join(::Rails.configuration.webpack.binary)
|
6
|
+
config_file = ::Rails.root.join(::Rails.configuration.webpack.config_file)
|
7
|
+
server_config_file = ::Rails.root.join(Vueport.config[:server_config_file])
|
8
|
+
|
9
|
+
unless File.exist?(webpack_bin)
|
10
|
+
raise "Can't find our webpack executable at #{webpack_bin} - have you run `npm install`?"
|
11
|
+
end
|
12
|
+
|
13
|
+
unless File.exist?(config_file)
|
14
|
+
raise "Can't find our webpack config file at #{config_file}"
|
15
|
+
end
|
16
|
+
|
17
|
+
unless File.exist?(server_config_file)
|
18
|
+
raise "Can't find our webpack server config file at #{config_file}"
|
19
|
+
end
|
20
|
+
|
21
|
+
sh "#{webpack_bin} --config #{config_file} --bail"
|
22
|
+
sh "#{webpack_bin} --config #{server_config_file} --bail"
|
23
|
+
end
|
24
|
+
end
|
data/lib/vueport.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
require 'vueport/helper'
|
4
|
+
require 'vueport/renderer'
|
5
|
+
require 'vueport/node_client'
|
6
|
+
require 'vueport/version'
|
7
|
+
|
8
|
+
module Vueport
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def config
|
12
|
+
@config ||= {
|
13
|
+
server_host: 'localhost',
|
14
|
+
server_port: 5000,
|
15
|
+
server_config_file: 'config/webpack.server.js',
|
16
|
+
ssr_enabled: false
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def configure(&_block)
|
21
|
+
yield config if block_given?
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'vueport/railtie' if defined? ::Rails::Railtie
|
@@ -0,0 +1,40 @@
|
|
1
|
+
|
2
|
+
module Vueport
|
3
|
+
class RenderError < StandardError; end
|
4
|
+
|
5
|
+
class NodeClient
|
6
|
+
attr_accessor :content
|
7
|
+
|
8
|
+
def initialize(content)
|
9
|
+
self.content = content
|
10
|
+
end
|
11
|
+
|
12
|
+
def run!
|
13
|
+
render.html_safe
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def render
|
19
|
+
raise(RenderError.new, response.body) if response.code != 200
|
20
|
+
response.body
|
21
|
+
end
|
22
|
+
|
23
|
+
def response
|
24
|
+
@response ||= HTTParty.post("http://#{server_uri}/render", post_params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def post_params
|
28
|
+
{
|
29
|
+
body: content,
|
30
|
+
headers: {
|
31
|
+
'Content-Type': 'text/plain'
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
def server_uri
|
37
|
+
"#{Vueport.config[:server_host]}:#{Vueport.config[:server_port]}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'rails/railtie'
|
3
|
+
require 'vueport'
|
4
|
+
|
5
|
+
module Vueport
|
6
|
+
# :nodoc:
|
7
|
+
class Railtie < ::Rails::Railtie
|
8
|
+
Vueport.configure do |config|
|
9
|
+
config[:ssr_enabled] = ::Rails.env.production?
|
10
|
+
end
|
11
|
+
|
12
|
+
config.after_initialize do
|
13
|
+
ActiveSupport.on_load(:action_view) do
|
14
|
+
include Vueport::Helper
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
rake_tasks do
|
19
|
+
load 'tasks/vueport.rake'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Vueport
|
2
|
+
class Renderer
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
|
5
|
+
CONTENT_WRAPPER_ID = 'vueport-wrapper'.freeze
|
6
|
+
TEMPLATE_ID = 'vueport-template'.freeze
|
7
|
+
|
8
|
+
attr_accessor :content
|
9
|
+
|
10
|
+
def initialize(content)
|
11
|
+
self.content = content
|
12
|
+
end
|
13
|
+
|
14
|
+
def render
|
15
|
+
safe_join [rendered_content, template]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def rendered_content
|
21
|
+
ssr_enabled? ? ssr_content : wrapper
|
22
|
+
end
|
23
|
+
|
24
|
+
def template
|
25
|
+
content_tag :script, wrapper(content), type: 'text/x-template', id: TEMPLATE_ID
|
26
|
+
end
|
27
|
+
|
28
|
+
def ssr_content
|
29
|
+
Vueport::NodeClient.new(wrapper(content)).run!
|
30
|
+
rescue Vueport::RenderError
|
31
|
+
wrapper
|
32
|
+
end
|
33
|
+
|
34
|
+
def wrapper(content = '')
|
35
|
+
content_tag :div, content, id: CONTENT_WRAPPER_ID
|
36
|
+
end
|
37
|
+
|
38
|
+
def ssr_enabled?
|
39
|
+
Vueport.config[:ssr_enabled]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/vueport.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'vueport/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'vueport'
|
8
|
+
spec.version = Vueport::VERSION
|
9
|
+
spec.authors = ['Sam Garson']
|
10
|
+
spec.email = ['samtgarson@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Single file components for Rails with Vue JS and Webpack'
|
13
|
+
spec.description = 'Use webpack and Vue js to get modern front end technology in your Rails app, including hotloading and single file components.'
|
14
|
+
spec.homepage = 'http://github.com/samtgarson/vueport'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.12'
|
23
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
24
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
25
|
+
spec.add_development_dependency 'rubocop', '~> 0.45.0'
|
26
|
+
spec.add_development_dependency 'rspec-html-matchers', '~> 0.8.1'
|
27
|
+
|
28
|
+
spec.add_dependency 'rails', '>= 3.2.0'
|
29
|
+
spec.add_dependency 'webpack-rails', '~> 0.9.9'
|
30
|
+
spec.add_dependency 'httparty', '~> 0.14.0'
|
31
|
+
|
32
|
+
spec.required_ruby_version = '>= 2.0.0'
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: vueport
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sam Garson
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.45.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.45.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec-html-matchers
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.8.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 0.8.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rails
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 3.2.0
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: 3.2.0
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webpack-rails
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.9.9
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.9.9
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: httparty
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.14.0
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: 0.14.0
|
125
|
+
description: Use webpack and Vue js to get modern front end technology in your Rails
|
126
|
+
app, including hotloading and single file components.
|
127
|
+
email:
|
128
|
+
- samtgarson@gmail.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- ".gitignore"
|
134
|
+
- ".rspec"
|
135
|
+
- ".rubocop.yml"
|
136
|
+
- ".travis.yml"
|
137
|
+
- CODE_OF_CONDUCT.md
|
138
|
+
- Gemfile
|
139
|
+
- LICENSE.txt
|
140
|
+
- README.md
|
141
|
+
- Rakefile
|
142
|
+
- bin/console
|
143
|
+
- bin/setup
|
144
|
+
- example/Procfile
|
145
|
+
- example/Procfile.dev
|
146
|
+
- example/application.js
|
147
|
+
- example/babelrc
|
148
|
+
- example/index.js
|
149
|
+
- example/server.js
|
150
|
+
- example/setup.js
|
151
|
+
- example/webpack.server.js
|
152
|
+
- lib/generators/vueport/install_generator.rb
|
153
|
+
- lib/tasks/vueport.rake
|
154
|
+
- lib/vueport.rb
|
155
|
+
- lib/vueport/helper.rb
|
156
|
+
- lib/vueport/node_client.rb
|
157
|
+
- lib/vueport/railtie.rb
|
158
|
+
- lib/vueport/renderer.rb
|
159
|
+
- lib/vueport/version.rb
|
160
|
+
- vueport.gemspec
|
161
|
+
homepage: http://github.com/samtgarson/vueport
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 2.0.0
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubyforge_project:
|
181
|
+
rubygems_version: 2.5.1
|
182
|
+
signing_key:
|
183
|
+
specification_version: 4
|
184
|
+
summary: Single file components for Rails with Vue JS and Webpack
|
185
|
+
test_files: []
|