webpacked 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/MIT-LICENSE +20 -0
- data/README.md +157 -0
- data/Rakefile +24 -0
- data/lib/capistrano/tasks/webpacked.rake +82 -0
- data/lib/capistrano/webpacked.rb +1 -0
- data/lib/generators/webpacked/USAGE +14 -0
- data/lib/generators/webpacked/install_generator.rb +53 -0
- data/lib/generators/webpacked/templates/Procfile +2 -0
- data/lib/generators/webpacked/templates/frontend/app/base-entry.js +1 -0
- data/lib/generators/webpacked/templates/frontend/base.config.js +57 -0
- data/lib/generators/webpacked/templates/frontend/dev-server.js +41 -0
- data/lib/generators/webpacked/templates/frontend/development.config.js +32 -0
- data/lib/generators/webpacked/templates/frontend/main.config.js +9 -0
- data/lib/generators/webpacked/templates/frontend/production.config.js +67 -0
- data/lib/generators/webpacked/templates/package.json +28 -0
- data/lib/webpacked/controller_helper.rb +18 -0
- data/lib/webpacked/helper.rb +42 -0
- data/lib/webpacked/manifest.rb +80 -0
- data/lib/webpacked/rails.rb +2 -0
- data/lib/webpacked/railtie.rb +30 -0
- data/lib/webpacked/version.rb +3 -0
- data/lib/webpacked.rb +1 -0
- metadata +94 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 2ce3d51fcf3507e85c3cbf4d1fcc7c69c87cb4e7
|
4
|
+
data.tar.gz: bf49978a1f8e89013bb85c874ad1bfc33a098898
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2c4a063a8c24b5dbe279bc6cc147eb527120a650dc1182bdc1625b0fcae431348f1988630ee93708d688bd9a054707ba0dd9df1e7db0f4ec0d42fb1d0249d579
|
7
|
+
data.tar.gz: 045b0f5f1f83a426f9546f926ee6902b366b9cef4f8d06968e4b87effebb91c86859620e12dc0514ed6468af912d33fcc490435d96140f6f04e4267292c88e38
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2016 Darkside73
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
[](https://travis-ci.org/Darkside73/webpacked) [](http://badge.fury.io/rb/webpacked)
|
2
|
+
|
3
|
+
# webpacked
|
4
|
+
|
5
|
+
**webpacked** helps you to integrate Webpack in to a Ruby on Rails application.
|
6
|
+
|
7
|
+
It can be used alongside sprockets but normaly you no need sprockets at all now: webpack replaces sprockets completely.
|
8
|
+
Using **webpacked** and webpack itself means that Javascript is a first-class citizen: you should use `npm` to manage packages (no more gemified Javascript libraries!).
|
9
|
+
|
10
|
+
In development mode assets are served via [webpack-dev-server](http://webpack.github.io/docs/webpack-dev-server.html) that brings a cool hot module reloading feature to your workflow. Webpack's manifest file is generated using [assets-webpack-plugin](https://github.com/kossnocorp/assets-webpack-plugin).
|
11
|
+
|
12
|
+
Also **webpacked** offers deploy automation within capistrano task (see detailed instructions bellow).
|
13
|
+
|
14
|
+
## Requirements
|
15
|
+
|
16
|
+
1. Node.js > 4
|
17
|
+
1. NPM > 3
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
1. Add `webpacked` to your Gemfile
|
22
|
+
1. Run `bundle install` to install the gem
|
23
|
+
1. Run `bin/rails generate webpacked:install` to get required files in your application, install NPM packages and foreman gem if you wish so
|
24
|
+
1. Run `foreman start` (if you've decided to install it) to start `webpack-dev-server` and `rails server` at the same time
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
### Webpack configuration
|
29
|
+
|
30
|
+
Webpack configs are divided into on three files:
|
31
|
+
|
32
|
+
1. `frontend/base.config.js` contains common setup for all environments
|
33
|
+
1. `frontend/development.config.js` contains setup specific for development
|
34
|
+
1. `frontend/production.config.js` includes production optimizations
|
35
|
+
|
36
|
+
Follow comments in these files and webpack official docs to conclude what meets you requirements.
|
37
|
+
|
38
|
+
Environment is defined via `NODE_ENV` variable and initialized in`frontend/main.config.js`. Normally you don't need to manual set up `NODE_ENV` unless you want to add another environment for your frontend application.
|
39
|
+
|
40
|
+
In development mode webpack-dev-server starts using `npm run dev:server` command or simply `foreman start`. Internally it uses `frontend/dev-server.js`.
|
41
|
+
|
42
|
+
Just in case there are a bunch other preconfigured NPM commands shipped (you can find them in the `package.json`):
|
43
|
+
|
44
|
+
* `npm run build:dev` runs webpack build for development environment
|
45
|
+
* `npm run build:production` same for production environment
|
46
|
+
|
47
|
+
### View helpers
|
48
|
+
|
49
|
+
To add webpacked assets in to your application, use following helpers:
|
50
|
+
|
51
|
+
```erb
|
52
|
+
<% # layout.html.erb %>
|
53
|
+
<!DOCTYPE html>
|
54
|
+
<html>
|
55
|
+
<head>
|
56
|
+
<%= webpacked_css_tags 'application' %>
|
57
|
+
</head>
|
58
|
+
<body>
|
59
|
+
<%= webpacked_js_tags 'application' %>
|
60
|
+
</body>
|
61
|
+
</html>
|
62
|
+
```
|
63
|
+
|
64
|
+
Where `'application'` is a one of the your entry points in webpack config.
|
65
|
+
|
66
|
+
NOTE: if you using [common chunks optimization](https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code) (it is so indeed in production most likely), these helpers may produce additional CSS/Javascript include tag for that common bundle.
|
67
|
+
|
68
|
+
You should not concern about including any extra scripts to get hot module reloading works: it integrates transparently through a same webpack manifest file.
|
69
|
+
|
70
|
+
### Controller helper
|
71
|
+
|
72
|
+
**webpacked** offers an optional approach to link entry points with Rails application. The idea is in mapping *controllers* to entry points. Consider the following code:
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
class ApplicationController < ActionController::Base
|
76
|
+
include Webpacked::ControllerHelper
|
77
|
+
webpacked_entry "application"
|
78
|
+
end
|
79
|
+
|
80
|
+
class FooController < ApplicationController
|
81
|
+
webpacked_entry "foo"
|
82
|
+
end
|
83
|
+
|
84
|
+
class BarController < ApplicationController
|
85
|
+
webpacked_entry "bar"
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
```erb
|
90
|
+
<%= webpacked_css_tags webpacked_entry_name %>
|
91
|
+
<%= webpacked_js_tags webpacked_entry_name %>
|
92
|
+
```
|
93
|
+
|
94
|
+
In the example above the decision which entry point to use comes in controllers instead views. Therefore in layout we can use a common `webpacked_entry_name` helper method. Notice that `webpacked_entry` in `ApplicationController` will be used if concrete controller does not define its own entry.
|
95
|
+
|
96
|
+
### Alternative ways
|
97
|
+
|
98
|
+
If you don't like none of the mentioned above, you can use more generic helpers to access webpack manifest:
|
99
|
+
|
100
|
+
* `asset_tag(entry, kind)` return include tags for entry point `entry`; `kind` could be `:js` or `:css`
|
101
|
+
* `webpacked_asset_path(entry, kind = nil)` return only assets path for given entry
|
102
|
+
|
103
|
+
Be aware that common entry point is not included by these methods. So if you use common chunks optimization do not forget to include `common` (or whatever name you pick) entry point manually.
|
104
|
+
|
105
|
+
### Rails configuration and other assumptions
|
106
|
+
|
107
|
+
Gem exposes a few configuration options:
|
108
|
+
|
109
|
+
* `webpacked.enabled` default to `true`; you probably want to disable webpacked in test environment, so helpers will not fail if manifest does not exist
|
110
|
+
* `webpacked.manifest_path` default to `webpack-assets.json`
|
111
|
+
* `webpacked.load_manifest_on_initialize` default to `false`; if `true` then parse manifest on application bootstrap
|
112
|
+
* `webpacked.common_entry_name` default to `common` (if you've changes this, you need to change it in webpack config as well)
|
113
|
+
* `webpacked.bin` default to `node_modules/.bin/webpack`
|
114
|
+
* `webpacked.config` default to `frontend/main.config.js`
|
115
|
+
* `webpacked.dev_server` enabled only in development mode
|
116
|
+
* webpack-dev-server starts on port 3500 on localhost via HTTP (use `WEBPACK_DEV_HOST` and `WEBPACK_DEV_PORT` env variables to change it)
|
117
|
+
* assets compiled to `public/assets/webpack`; you can change it in webpack config (and `deploy.rb` if capistrano webpacked task used)
|
118
|
+
|
119
|
+
## Capistrano deployment
|
120
|
+
|
121
|
+
### Installation and usage
|
122
|
+
|
123
|
+
To deploy generated assets add `require "capistrano/webpacked"` to your `Capfile`. The `deploy:webpacked:build` task will run automaticaly as after `deploy:updated` hook.
|
124
|
+
|
125
|
+
Also you need to set up the `:assets_roles` in `deploy.rb` so **webpacked** to run its tasks.
|
126
|
+
|
127
|
+
What under hood? The task makes diff of files and folders (specified in `:webpacked_dependencies` option) in current release against previous release and decides whether to run production webpack build. If there is no diff then simply a manifest copied from previous release path. If some of dependencies were changed then production build starts *locally* and assets synchronized via `rsync` over SSH.
|
128
|
+
|
129
|
+
NOTE: scince webpack build runs locally, you should pay an extra attention to your working copy condition: current branch, not published commits, not commited changes, etc.
|
130
|
+
|
131
|
+
Additionally there are some extra tasks exposed (they are used by `deploy:webpacked:build` internally):
|
132
|
+
|
133
|
+
* `deploy:webpacked:build_force` unconditionally invokes production build on local machine
|
134
|
+
* `deploy:webpacked:sync` synchronize assets under `:webpacked_release_output_path` with remote server
|
135
|
+
|
136
|
+
### Configuration
|
137
|
+
|
138
|
+
There are following options available to set up (example values are defaults in fact):
|
139
|
+
|
140
|
+
* `set :webpacked_dependencies, %w(frontend npm-shrinkwrap.json)` webpacked build will perform if one of these will be changed
|
141
|
+
* `set :webpacked_manifest_path, "webpack-assets.json"` same as `Rails.configuration.webpacked.manifest_path`
|
142
|
+
* `set :webpacked_deploy_manifest_path, "webpack-assets-deploy.json"` used for production manifest only; choose another path to not clash with local dev manifest
|
143
|
+
* `set :webpacked_local_output_path, "public/#{fetch(:assets_prefix)}/webpack"` where webpack generates its assets
|
144
|
+
* `set :webpacked_release_output_path, "public/#{fetch(:assets_prefix)}/webpack"` where webpack assets are stored on the deploy server (started from `shared_path`)
|
145
|
+
|
146
|
+
## TODO
|
147
|
+
|
148
|
+
* deploy with remote webpack build performing
|
149
|
+
|
150
|
+
## Contributing
|
151
|
+
|
152
|
+
Pull requests, issues and discussion are welcomed
|
153
|
+
|
154
|
+
## Thanks
|
155
|
+
|
156
|
+
* Marketplacer team for their [webpack-rails](https://github.com/mipearson/webpack-rails) gem which guides this implementation in some way ;)
|
157
|
+
* Contributors of [capistrano-faster-assets](https://github.com/capistrano-plugins/capistrano-faster-assets) gem for conditionally assets compile idea
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
require 'rubocop/rake_task'
|
10
|
+
|
11
|
+
RuboCop::RakeTask.new
|
12
|
+
RSpec::Core::RakeTask.new(:spec)
|
13
|
+
|
14
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
15
|
+
rdoc.rdoc_dir = 'rdoc'
|
16
|
+
rdoc.title = 'Webpacked'
|
17
|
+
rdoc.options << '--line-numbers'
|
18
|
+
rdoc.rdoc_files.include('README.md')
|
19
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'bundler/gem_tasks'
|
23
|
+
|
24
|
+
task default: [:spec, :rubocop]
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# based on capistrano-faster-assets gem
|
2
|
+
|
3
|
+
class WebpackedBuildRequired < StandardError; end
|
4
|
+
|
5
|
+
namespace :deploy do
|
6
|
+
namespace :webpacked do
|
7
|
+
OPTIONS = lambda do |option|
|
8
|
+
{
|
9
|
+
dependencies: fetch(:webpacked_dependencies) || %w(frontend npm-shrinkwrap.json),
|
10
|
+
manifest_path: fetch(:webpacked_manifest_path) || 'webpack-assets.json',
|
11
|
+
deploy_manifest_path: fetch(:webpacked_local_manifest_path) || 'webpack-assets-deploy.json',
|
12
|
+
local_output_path: fetch(:webpacked_local_output_path) || "public/#{fetch(:assets_prefix)}/webpack",
|
13
|
+
release_output_path: fetch(:webpacked_release_output_path) || "public/#{fetch(:assets_prefix)}/webpack"
|
14
|
+
}.fetch(option)
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Webpack build assets'
|
18
|
+
task :build do
|
19
|
+
on roles(fetch(:assets_roles)) do
|
20
|
+
with rails_env: fetch(:rails_env) do
|
21
|
+
begin
|
22
|
+
latest_release = capture(:ls, '-xr', releases_path).split[1]
|
23
|
+
raise WebpackedBuildRequired unless latest_release
|
24
|
+
latest_release_path = releases_path.join(latest_release)
|
25
|
+
|
26
|
+
OPTIONS.(:dependencies).each do |dep|
|
27
|
+
release = release_path.join(dep)
|
28
|
+
latest = latest_release_path.join(dep)
|
29
|
+
# skip if both directories/files do not exist
|
30
|
+
next if [release, latest].map { |d| test "test -e #{d}" }.uniq == [false]
|
31
|
+
# execute raises if there is a diff
|
32
|
+
begin
|
33
|
+
execute(:diff, '-Nqr', release, latest)
|
34
|
+
rescue SSHKit::Runner::ExecuteError
|
35
|
+
raise WebpackedBuildRequired
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
info 'Skipping webpack build, no diff found'
|
40
|
+
|
41
|
+
execute(
|
42
|
+
:cp,
|
43
|
+
latest_release_path.join(OPTIONS.(:manifest_path)),
|
44
|
+
release_path.join(OPTIONS.(:manifest_path))
|
45
|
+
)
|
46
|
+
rescue WebpackedBuildRequired
|
47
|
+
invoke 'deploy:webpacked:build_force'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
after 'deploy:updated', 'deploy:webpacked:build'
|
53
|
+
|
54
|
+
task :build_force do
|
55
|
+
run_locally do
|
56
|
+
info 'Create webpack local build'
|
57
|
+
`RAILS_ENV=#{fetch(:rails_env)} npm run build:production`
|
58
|
+
invoke 'deploy:webpacked:sync'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Sync locally compiled assets with current release path'
|
63
|
+
|
64
|
+
task :sync do
|
65
|
+
on roles(fetch(:assets_roles)) do
|
66
|
+
info 'Sync assets...'
|
67
|
+
upload!(
|
68
|
+
OPTIONS.(:deploy_manifest_path),
|
69
|
+
release_path.join(OPTIONS.(:manifest_path))
|
70
|
+
)
|
71
|
+
execute(:mkdir, '-p', shared_path.join(OPTIONS.(:release_output_path)))
|
72
|
+
end
|
73
|
+
roles(fetch(:assets_roles)).each do |host|
|
74
|
+
run_locally do
|
75
|
+
local_output_path = fetch(:webpacked_local_output_path)
|
76
|
+
release_output_path = shared_path.join(OPTIONS.(:release_output_path))
|
77
|
+
`rsync -avzr --delete #{local_output_path} #{host.user}@#{host.hostname}:#{release_output_path.parent}`
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
load File.expand_path('../tasks/webpacked.rake', __FILE__)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Description:
|
2
|
+
Install basic configs for webpacked integration
|
3
|
+
|
4
|
+
Example:
|
5
|
+
bin/rails generate webpacked:install
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
frontend/app
|
9
|
+
frontend/lib
|
10
|
+
frontend/base.config.js
|
11
|
+
frontend/development.config.js
|
12
|
+
frontend/main.config.js
|
13
|
+
frontend/production.config.js
|
14
|
+
frontend/dev-server.js
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Webpacked
|
2
|
+
# :nodoc:
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
def use_foreman
|
7
|
+
if yes?('Would you like to use foreman to start webpack-dev-server and rails server at same time?')
|
8
|
+
gem 'foreman'
|
9
|
+
copy_file 'Procfile'
|
10
|
+
run 'bundle install' if yes?("Run 'bundle install' for you?")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def copy_frontend_dir
|
15
|
+
directory 'frontend'
|
16
|
+
end
|
17
|
+
|
18
|
+
def prepare_package_json
|
19
|
+
get 'package.json' do |content|
|
20
|
+
content.gsub!(/\{\{(.+?)\}\}/) do
|
21
|
+
Rails.configuration.webpacked.send(Regexp.last_match(1))
|
22
|
+
end
|
23
|
+
create_file 'package.json', content
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_to_gitignore
|
28
|
+
append_to_file '.gitignore' do
|
29
|
+
<<-EOF.strip_heredoc
|
30
|
+
# Added by webpacked
|
31
|
+
/node_modules
|
32
|
+
/public/assets/webpacked
|
33
|
+
EOF
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_npm_install
|
38
|
+
run 'npm install' if yes?("Run 'npm install' for you?")
|
39
|
+
end
|
40
|
+
|
41
|
+
def whats_next
|
42
|
+
puts <<-EOF.strip_heredoc
|
43
|
+
Base webpacked setup completed. Now you can:
|
44
|
+
1. Include 'Webpacked::ControllerHelper' into 'ApplicationController'
|
45
|
+
and set up entry points for your controllers via 'webpacked_entry' class method
|
46
|
+
2. Add the webpacked helpers into your layout instead of regular Rails helpers
|
47
|
+
3. Run 'npm run dev:server' to start webpack-dev-server or 'foreman start' to start it alongside rails server
|
48
|
+
See https://github.com/Darkside73/webpacked for more info.
|
49
|
+
Thanks for using webpacked gem ;)
|
50
|
+
EOF
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
console.log("Hello from webpacked!")
|
@@ -0,0 +1,57 @@
|
|
1
|
+
const path = require('path')
|
2
|
+
const webpack = require('webpack')
|
3
|
+
|
4
|
+
module.exports = {
|
5
|
+
context: __dirname,
|
6
|
+
output: {
|
7
|
+
// where to generate webpack assets
|
8
|
+
path: path.join(__dirname, '..', 'public', 'assets', 'webpack'),
|
9
|
+
filename: 'bundle-[name].js'
|
10
|
+
},
|
11
|
+
entry: {
|
12
|
+
application: ['./app/base-entry'],
|
13
|
+
},
|
14
|
+
resolve: {
|
15
|
+
// Default extensions to require file without extension
|
16
|
+
extensions: ['', '.js'],
|
17
|
+
modulesDirectories: [ 'node_modules' ],
|
18
|
+
alias: {
|
19
|
+
// Handy shortcut: use absolute path `require(~lib/mylib)` from any place
|
20
|
+
lib: path.join(__dirname, 'lib'),
|
21
|
+
}
|
22
|
+
},
|
23
|
+
module: {
|
24
|
+
// Loaders with identical settings for both
|
25
|
+
// development and production environments
|
26
|
+
loaders: [
|
27
|
+
|
28
|
+
// Use ES6 syntax (highly recommended!)
|
29
|
+
// (run `npm install babel-loader babel-core babel-preset-es2015 --save-dev`)
|
30
|
+
// {
|
31
|
+
// test: /\.js$/,
|
32
|
+
// include: [ path.resolve(__dirname + 'frontend/app') ],
|
33
|
+
// loader: 'babel?presets[]=es2015'
|
34
|
+
// },
|
35
|
+
|
36
|
+
// Use Coffescript
|
37
|
+
// { test: /\.coffee$/, loader: 'coffee-loader' },
|
38
|
+
|
39
|
+
// Use Vue.js framework (run `npm install vue vue-loader --save-dev`)
|
40
|
+
// { test: /\.vue$/, loader: 'vue' },
|
41
|
+
|
42
|
+
// Makes `$` and `jQuery` available globally
|
43
|
+
// { test: require.resolve('jquery'), loader: 'expose?$!expose?jQuery' }
|
44
|
+
],
|
45
|
+
},
|
46
|
+
plugins: [
|
47
|
+
// new webpack.ProvidePlugin({
|
48
|
+
// $: 'jquery',
|
49
|
+
// jQuery: 'jquery',
|
50
|
+
// }),
|
51
|
+
|
52
|
+
// Use `__RAILS_ENV__` variable in your Javascript code
|
53
|
+
// new webpack.DefinePlugin({
|
54
|
+
// __RAILS_ENV__: JSON.stringify(process.env.RAILS_ENV || 'production'),
|
55
|
+
// })
|
56
|
+
]
|
57
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
const webpack = require('webpack')
|
2
|
+
const WebpackDevServer = require('webpack-dev-server')
|
3
|
+
const config = require('./main.config')
|
4
|
+
const webpackDevHost = process.env.WEBPACK_DEV_HOST || 'localhost'
|
5
|
+
const webpackDevPort = process.env.WEBPACK_DEV_PORT || 3500
|
6
|
+
|
7
|
+
config.output.publicPath = `http://${webpackDevHost}:${webpackDevPort}/assets/`;
|
8
|
+
for (var entryName in config.entry) {
|
9
|
+
config.entry[entryName].push(
|
10
|
+
`webpack-dev-server/client?http://${webpackDevHost}:${webpackDevPort}`,
|
11
|
+
'webpack/hot/only-dev-server'
|
12
|
+
)
|
13
|
+
}
|
14
|
+
|
15
|
+
config.plugins.push(
|
16
|
+
new webpack.optimize.OccurenceOrderPlugin(),
|
17
|
+
new webpack.HotModuleReplacementPlugin(),
|
18
|
+
new webpack.NoErrorsPlugin()
|
19
|
+
)
|
20
|
+
|
21
|
+
new WebpackDevServer(webpack(config), {
|
22
|
+
publicPath: config.output.publicPath,
|
23
|
+
hot: true,
|
24
|
+
inline: true,
|
25
|
+
historyApiFallback: true,
|
26
|
+
quiet: false,
|
27
|
+
noInfo: false,
|
28
|
+
lazy: false,
|
29
|
+
stats: {
|
30
|
+
colors: true,
|
31
|
+
hash: false,
|
32
|
+
version: false,
|
33
|
+
chunks: false,
|
34
|
+
children: false,
|
35
|
+
}
|
36
|
+
}).listen(webpackDevPort, webpackDevHost, function (err, result) {
|
37
|
+
if (err) console.log(err)
|
38
|
+
console.log(
|
39
|
+
`=> 🔥 Webpack development server is running on port ${webpackDevPort}`
|
40
|
+
)
|
41
|
+
})
|
@@ -0,0 +1,32 @@
|
|
1
|
+
const AssetsPlugin = require('assets-webpack-plugin')
|
2
|
+
|
3
|
+
module.exports = {
|
4
|
+
debug: true,
|
5
|
+
displayErrorDetails: true,
|
6
|
+
outputPathinfo: true,
|
7
|
+
devtool: 'eval-source-map',
|
8
|
+
output: {
|
9
|
+
devtoolModuleFilenameTemplate: '[resourcePath]',
|
10
|
+
devtoolFallbackModuleFilenameTemplate: '[resourcePath]?[hash]'
|
11
|
+
},
|
12
|
+
module: {
|
13
|
+
loaders: [
|
14
|
+
{ test: /\.css$/, loader: 'style!css?sourceMap' },
|
15
|
+
// {
|
16
|
+
// test: /\.scss$/,
|
17
|
+
// loader: 'style!css?sourceMap!resolve-url!sass?sourceMap'
|
18
|
+
// },
|
19
|
+
{
|
20
|
+
test: /\.(png|jpg|gif)$/,
|
21
|
+
loader: 'url?name=[path][name].[ext]&limit=8192'
|
22
|
+
},
|
23
|
+
{
|
24
|
+
test: /\.(ttf|eot|svg|woff(2)?)(\?.+)?$/,
|
25
|
+
loader: 'file?name=[path][name].[ext]'
|
26
|
+
},
|
27
|
+
]
|
28
|
+
},
|
29
|
+
plugins: [
|
30
|
+
new AssetsPlugin({ prettyPrint: true }),
|
31
|
+
]
|
32
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
const path = require('path')
|
2
|
+
const webpack = require('webpack')
|
3
|
+
const CleanPlugin = require('clean-webpack-plugin')
|
4
|
+
const ExtractTextPlugin = require("extract-text-webpack-plugin")
|
5
|
+
// const CompressionPlugin = require("compression-webpack-plugin")
|
6
|
+
const AssetsPlugin = require('assets-webpack-plugin')
|
7
|
+
|
8
|
+
module.exports = {
|
9
|
+
output: {
|
10
|
+
filename: './bundle-[name]-[chunkhash].js',
|
11
|
+
chunkFilename: 'bundle-[name]-[chunkhash].js',
|
12
|
+
publicPath: '/assets/webpack/'
|
13
|
+
},
|
14
|
+
module: {
|
15
|
+
loaders: [
|
16
|
+
{
|
17
|
+
test: /\.css$/,
|
18
|
+
loader: ExtractTextPlugin.extract("style-loader", "css?minimize")
|
19
|
+
},
|
20
|
+
// {
|
21
|
+
// test: /\.scss$/,
|
22
|
+
// loader: ExtractTextPlugin.extract(
|
23
|
+
// "style-loader", "css?minimize!resolve-url!sass?sourceMap"
|
24
|
+
// )
|
25
|
+
// },
|
26
|
+
{ test: /\.(png|jpg|gif)$/, loader: 'url?limit=8192' },
|
27
|
+
{
|
28
|
+
test: /\.(ttf|eot|svg|woff(2)?)(\?.+)?$/,
|
29
|
+
loader: 'file'
|
30
|
+
},
|
31
|
+
]
|
32
|
+
},
|
33
|
+
plugins: [
|
34
|
+
// Creates separate manifest for production
|
35
|
+
new AssetsPlugin({
|
36
|
+
prettyPrint: true, filename: 'webpack-assets-deploy.json'
|
37
|
+
}),
|
38
|
+
|
39
|
+
// Extacts CSS to stanalone file
|
40
|
+
new ExtractTextPlugin("bundle-[name]-[chunkhash].css", {
|
41
|
+
allChunks: true
|
42
|
+
}),
|
43
|
+
|
44
|
+
new CleanPlugin(
|
45
|
+
path.join('public', 'assets', 'webpack'),
|
46
|
+
{ root: path.join(process.cwd()) }
|
47
|
+
),
|
48
|
+
|
49
|
+
// Some webpack built-in optimizations
|
50
|
+
// Fill free to switch off if don't need some of it
|
51
|
+
new webpack.optimize.CommonsChunkPlugin('common', 'bundle-[name]-[hash].js'),
|
52
|
+
new webpack.optimize.DedupePlugin(),
|
53
|
+
new webpack.optimize.OccurenceOrderPlugin(),
|
54
|
+
|
55
|
+
//Enables Javascript source code uglifying
|
56
|
+
// new webpack.optimize.UglifyJsPlugin({
|
57
|
+
// mangle: true,
|
58
|
+
// compress: {
|
59
|
+
// warnings: false
|
60
|
+
// }
|
61
|
+
// }),
|
62
|
+
|
63
|
+
// Enables gzip compression for Javascript and CSS assets
|
64
|
+
// (remember to uncomment corresponding `require` on top of this file)
|
65
|
+
// new CompressionPlugin({ test: /\.js$|\.css$/ }),
|
66
|
+
]
|
67
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
{
|
2
|
+
"name": "your-app-name",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"devDependencies": {
|
6
|
+
"assets-webpack-plugin": "^3.2.0",
|
7
|
+
"clean-webpack-plugin": "^0.1.6",
|
8
|
+
"css-loader": "^0.23.1",
|
9
|
+
"exports-loader": "^0.6.2",
|
10
|
+
"expose-loader": "^0.7.1",
|
11
|
+
"extract-text-webpack-plugin": "^1.0.0",
|
12
|
+
"file-loader": "^0.8.5",
|
13
|
+
"style-loader": "^0.13.0",
|
14
|
+
"url-loader": "^0.5.7",
|
15
|
+
"webpack": "^1.12.9",
|
16
|
+
"webpack-dev-server": "^1.14.0",
|
17
|
+
"webpack-hot-middleware": "^2.6.0",
|
18
|
+
"webpack-merge": "^0.6.0"
|
19
|
+
},
|
20
|
+
"scripts": {
|
21
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
22
|
+
"build:dev": "{{bin}} -v --config {{config}} --display-chunks --debug",
|
23
|
+
"build:production": "NODE_ENV=production {{bin}} -v --config {{config}} --display-chunks",
|
24
|
+
"dev:server": "node frontend/dev-server.js"
|
25
|
+
},
|
26
|
+
"author": "",
|
27
|
+
"license": "ISC"
|
28
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Webpacked
|
2
|
+
# Mixin for Rails controllers
|
3
|
+
module ControllerHelper
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
# :nodoc:
|
7
|
+
module ClassMethods
|
8
|
+
# Mix in controller's class method to set up an entry point name
|
9
|
+
# and reveal +webpacked_entry_name+ helper to get this name in view
|
10
|
+
def webpacked_entry(name)
|
11
|
+
helper_method :webpacked_entry_name
|
12
|
+
cattr_accessor :webpacked_entry_name
|
13
|
+
|
14
|
+
self.webpacked_entry_name = name
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Webpacked
|
2
|
+
# Add new view helpers
|
3
|
+
module Helper
|
4
|
+
# Return +javascript_include_tag+ for entry point.
|
5
|
+
# Also common Javascript file could be included
|
6
|
+
def webpacked_js_tags(entry)
|
7
|
+
webpacked_tags entry, :js
|
8
|
+
end
|
9
|
+
|
10
|
+
# Return +stylesheet_link_tag+ for entry point.
|
11
|
+
# Also common CSS file could be included
|
12
|
+
def webpacked_css_tags(entry)
|
13
|
+
webpacked_tags entry, :css
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return include tags for entry point by given asset kind.
|
17
|
+
# Also common file could be included
|
18
|
+
def webpacked_tags(entry, kind)
|
19
|
+
common_entry = ::Rails.configuration.webpacked.common_entry_name
|
20
|
+
common_bundle = asset_tag(common_entry, kind)
|
21
|
+
page_bundle = asset_tag(entry, kind)
|
22
|
+
common_bundle ? common_bundle + page_bundle : page_bundle
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return include tags for entry point by given asset kind.
|
26
|
+
# No extra common file included even if it exists
|
27
|
+
def asset_tag(entry, kind)
|
28
|
+
path = webpacked_asset_path(entry, kind)
|
29
|
+
if path
|
30
|
+
case kind
|
31
|
+
when :js then javascript_include_tag path
|
32
|
+
when :css then stylesheet_link_tag path
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Alias for Webpacked::Manifest.asset_paths
|
38
|
+
def webpacked_asset_path(entry, kind = nil)
|
39
|
+
Webpacked::Manifest.asset_paths(entry, kind)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Webpacked
|
2
|
+
# Webpack manifest loading, caching and entry point retrieval
|
3
|
+
class Manifest
|
4
|
+
ASSET_KINDS = [:js, :css]
|
5
|
+
|
6
|
+
# Raised if webpack manifest not readable for whatever reason
|
7
|
+
class LoadError < StandardError
|
8
|
+
end
|
9
|
+
|
10
|
+
# Raised if something but +:js+ or +:css+ passed as asset kind
|
11
|
+
class UnknownAssetKindError < StandardError
|
12
|
+
def initialize(kind)
|
13
|
+
super "Unknown asset kind: #{kind}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Raised if an entry point does not exist in the webpack manifest
|
18
|
+
class EntryMissingError < StandardError
|
19
|
+
def initialize(entry)
|
20
|
+
super "Entry point is missed: #{entry}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Load manifest from file and cache it if +Rails.configuration.webpacked.dev_server+ set to +false+.
|
26
|
+
# Return entry point asset path for +:js+ or +:css+ kind or both if +kind+ skipped
|
27
|
+
def asset_paths(entry, kind = nil)
|
28
|
+
validate_asset_kind(kind)
|
29
|
+
if Rails.configuration.webpacked.dev_server
|
30
|
+
@manifest = load_manifest!
|
31
|
+
else
|
32
|
+
@manifest ||= load_manifest!
|
33
|
+
end
|
34
|
+
validate_entry(entry)
|
35
|
+
|
36
|
+
return @manifest[entry] unless kind
|
37
|
+
return @manifest[entry][kind] if @manifest[entry]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Force to load manifest from file
|
41
|
+
def load_manifest!
|
42
|
+
manifest_path = Rails.configuration.webpacked.manifest_path
|
43
|
+
manifest_path = Rails.root.join(manifest_path)
|
44
|
+
manifest = {}
|
45
|
+
if File.exist?(manifest_path)
|
46
|
+
manifest = JSON.parse(File.read manifest_path).with_indifferent_access
|
47
|
+
clean_asset_paths(manifest)
|
48
|
+
elsif Rails.configuration.webpacked.enabled
|
49
|
+
raise LoadError, "File #{manifest_path} not found"
|
50
|
+
end
|
51
|
+
manifest
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def validate_asset_kind(kind)
|
57
|
+
return unless kind
|
58
|
+
raise UnknownAssetKindError, kind unless ASSET_KINDS.include?(kind)
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_entry(entry)
|
62
|
+
unless entry == Rails.configuration.webpacked.common_entry_name
|
63
|
+
raise EntryMissingError, entry unless @manifest[entry]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def clean_asset_paths(manifest)
|
68
|
+
manifest.each do |entry, assets|
|
69
|
+
assets.each do |kind, asset_path|
|
70
|
+
manifest[entry][kind] = if asset_path =~ %r{(http[s]?)://}i
|
71
|
+
asset_path
|
72
|
+
else
|
73
|
+
Pathname.new(asset_path).cleanpath.to_s
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rails'
|
2
|
+
require 'rails/railtie'
|
3
|
+
require 'webpacked/manifest'
|
4
|
+
require 'webpacked/helper'
|
5
|
+
require 'webpacked/controller_helper'
|
6
|
+
|
7
|
+
module Webpacked
|
8
|
+
# :nodoc:
|
9
|
+
class Railtie < ::Rails::Railtie
|
10
|
+
config.webpacked = ActiveSupport::OrderedOptions.new
|
11
|
+
|
12
|
+
config.webpacked.enabled = true
|
13
|
+
config.webpacked.manifest_path = 'webpack-assets.json'
|
14
|
+
config.webpacked.load_manifest_on_initialize = false
|
15
|
+
config.webpacked.common_entry_name = 'common'
|
16
|
+
config.webpacked.bin = 'node_modules/.bin/webpack'
|
17
|
+
config.webpacked.config = 'frontend/main.config.js'
|
18
|
+
config.webpacked.dev_server = Rails.env.development?
|
19
|
+
|
20
|
+
initializer 'webpacked.load_manifest' do
|
21
|
+
Webpacked::Manifest.load_manifest! if Rails.configuration.webpacked.load_manifest_on_initialize
|
22
|
+
end
|
23
|
+
|
24
|
+
config.after_initialize do
|
25
|
+
ActiveSupport.on_load(:action_view) do
|
26
|
+
include Webpacked::Helper
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/webpacked.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'webpacked/rails'
|
metadata
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webpacked
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrey Garbuz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-08-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 3.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 3.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: Ready for production gem to use webpack and hot reload within Rails application
|
42
|
+
email:
|
43
|
+
- andrey.garbuz@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- MIT-LICENSE
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- lib/capistrano/tasks/webpacked.rake
|
52
|
+
- lib/capistrano/webpacked.rb
|
53
|
+
- lib/generators/webpacked/USAGE
|
54
|
+
- lib/generators/webpacked/install_generator.rb
|
55
|
+
- lib/generators/webpacked/templates/Procfile
|
56
|
+
- lib/generators/webpacked/templates/frontend/app/base-entry.js
|
57
|
+
- lib/generators/webpacked/templates/frontend/base.config.js
|
58
|
+
- lib/generators/webpacked/templates/frontend/dev-server.js
|
59
|
+
- lib/generators/webpacked/templates/frontend/development.config.js
|
60
|
+
- lib/generators/webpacked/templates/frontend/main.config.js
|
61
|
+
- lib/generators/webpacked/templates/frontend/production.config.js
|
62
|
+
- lib/generators/webpacked/templates/package.json
|
63
|
+
- lib/webpacked.rb
|
64
|
+
- lib/webpacked/controller_helper.rb
|
65
|
+
- lib/webpacked/helper.rb
|
66
|
+
- lib/webpacked/manifest.rb
|
67
|
+
- lib/webpacked/rails.rb
|
68
|
+
- lib/webpacked/railtie.rb
|
69
|
+
- lib/webpacked/version.rb
|
70
|
+
homepage: https://github.com/Darkside73/webpacked
|
71
|
+
licenses:
|
72
|
+
- MIT
|
73
|
+
metadata: {}
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options: []
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.2.2
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
requirements: []
|
89
|
+
rubyforge_project:
|
90
|
+
rubygems_version: 2.6.6
|
91
|
+
signing_key:
|
92
|
+
specification_version: 4
|
93
|
+
summary: Easy webpack and Rails integration
|
94
|
+
test_files: []
|