repack 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: adec7fb8dd623e161217547c202c16ce14c70c26
4
+ data.tar.gz: f7ade025adcf0f7a2a5a5ba811bdb6d13b6ed0ef
5
+ SHA512:
6
+ metadata.gz: 7dca33c49c3202d25fa7cd731b639bd8dbf0d7b410938a238b041f398964d508da2acb8e5b49fa558067a78f9115f8260839456e311a7e5b4585542cb8327f65
7
+ data.tar.gz: c80d97d626c0652a1f1162422e2e57b30d909982bbfad19d6cd3d249044ea78afb09a6309edb1497c3355c10e34ccaad3d84951a0ddc59d9426bcd99a719ef4c
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Michael Pearson
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,127 @@
1
+ # repack
2
+
3
+ **repack** gives you tools to integrate Webpack and React in to an existing Ruby on Rails application.
4
+
5
+ It will happily co-exist with sprockets but does not use it for production fingerprinting or asset serving. **repack** is designed with the assumption that if you're using Webpack you treat Javascript as a first-class citizen. This means that you control the webpack config, package.json, and use npm to install Webpack & its plugins.
6
+
7
+ In development mode [webpack-dev-server](http://webpack.github.io/docs/webpack-dev-server.html) is used to serve webpacked entry points and offer hot module reloading. In production entry points are built in to `public/client`. **repack** uses [stats-webpack-plugin](https://www.npmjs.com/package/stats-webpack-plugin) to translate entry points in to asset paths.
8
+
9
+ It was forked from the [Marketplacer](http://www.marketplacer.com) repo: (https://github.com/mipearson/webpack-rails) and support for React / Babel / ES6 was added.
10
+
11
+ This gem has been tested against Rails 4.2 and Ruby 2.2. Earlier versions of Rails (>= 3.2) and Ruby (>= 1.9) may work, but we haven't tested them.
12
+
13
+ ## Using repack
14
+
15
+ ### Install Flags
16
+ 1. No Flags -> Basic Webpack and React Boilerplate
17
+ 2. --router -> Webpack / React / React Router Boilerplate
18
+ 3. --redux -> Webpack / React / Redux Boilerplate
19
+ 4. --router --redux -> Webpack / React / Router / Redux Boilerplate
20
+
21
+ ### Installation
22
+
23
+ 1. Add `repack` to your gemfile
24
+ 2. Run `bundle install` to install the gem
25
+ 3. Run `bundle exec rails generate repack:install` to copy across example files
26
+ 4. Run `npm run dev_server` to start `webpack-dev-server`
27
+ 5. Add the webpack entry point to your layout (see next section)
28
+ 6. Edit `client/application.js` and write some code
29
+
30
+ ### Adding the entry point to your Rails application
31
+
32
+ To add your webpacked javascript in to your app, add the following to the `<body>` section of any layout by default it has been added to `layout.html.erb`:
33
+
34
+ ```erb
35
+ <%= javascript_include_tag *webpack_asset_paths("application") %>
36
+ ```
37
+
38
+ Take note of the splat (`*`): `webpack_asset_paths` returns an array, as one entry point can map to multiple paths, especially if hot reloading is enabled in Webpack.
39
+
40
+ #### Use with webpack-dev-server live reload
41
+
42
+ If you're using the webpack dev server's live reload feature (not the React hot reloader), you'll also need to include the following in your layout template:
43
+
44
+ ``` html
45
+ <script src="http://localhost:3808/webpack-dev-server.js"></script>
46
+ ```
47
+
48
+ This has been added to layouts/index.html.erb by default.
49
+
50
+ ### Configuration Defaults
51
+
52
+ * Webpack configuration lives in `config/webpack.config.js`
53
+ * Webpack & Webpack Dev Server binaries are in `node_modules/.bin/`
54
+ * Webpack Dev Server will run on port 3808 on localhost via HTTP
55
+ * Webpack Dev Server is enabled in development & test, but not in production
56
+ * Webpacked assets will be compiled to `public/client`
57
+ * The manifest file is named `manifest.json`
58
+
59
+ ### Working with browser tests
60
+
61
+ In development, we make sure that the `webpack-dev-server` is running when browser tests are running.
62
+
63
+ #### Continuous Integration
64
+
65
+ In CI, we manually run `webpack` to compile the assets to public and set `config.webpack.dev_server.enabled` to `false` in our `config/environments/test.rb`:
66
+
67
+ ``` ruby
68
+ config.webpack.dev_server.enabled = !ENV['CI']
69
+ ```
70
+
71
+ ### Production Deployment
72
+
73
+ If deploying to heroku, you will need to set your buildpacks before pushing. After adding the heroku git remote, run the below three commands:
74
+
75
+ ```
76
+ heroku buildpacks:clear
77
+ heroku buildpacks:set heroku/nodejs
78
+ heroku buildpacks:add heroku/ruby --index 2
79
+ ```
80
+
81
+ This will set the Node.js buildpack to run first, followed by the Ruby buildpack. To confirm that your buildpacks are set correctly, run `heroku buildpacks`. You should see Node.js listed first and Ruby second.
82
+
83
+ Next you will need to set up a post build hook to bundle Webpack. Include the below scripts in `package.json`. For the Webpack deployment script, ensure that the route for your `webpack.config.js` file is correct.
84
+
85
+ ``` javascript
86
+ "scripts": {
87
+ "webpack:deploy": "webpack --config=config/webpack.config.js -p",
88
+ "heroku-postbuild": "npm run webpack:deploy"
89
+ }
90
+ ```
91
+
92
+ Lastly, ensure that all Babel related modules are listed as dependencies and not dev dependencies in `package.json`. At this point, you should be able to push to Heroku.
93
+
94
+ An alternative to adding the post build hook to `package.json` is to add `rake webpack:compile` to your deployment. It serves a similar purpose as Sprockets' `assets:precompile` task. If you're using Webpack and Sprockets (as we are at Marketplacer) you'll need to run both tasks - but it doesn't matter which order they're run in.
95
+
96
+ If you're using `[chunkhash]` in your build asset filenames (which you should be, if you want to cache them in production), you'll need to persist built assets between deployments. Consider in-flight requests at the time of deployment: they'll receive paths based on the old `manifest.json`, not the new one.
97
+
98
+ ## Example Apps
99
+ * [basic](https://github.com/cottonwoodcoding/webpack-rails-react-basic)
100
+ * [react-router](https://github.com/cottonwoodcoding/webpack-rails-react-router)
101
+ * [redux](https://github.com/cottonwoodcoding/webpack-rails-react-redux)
102
+ * [redux react-router](https://github.com/cottonwoodcoding/webpack-rails-react-redux-router)
103
+
104
+ ## TODO
105
+
106
+ * Add eslint to client
107
+ * Integration tests
108
+ * Port example apps to Repack
109
+
110
+
111
+ ## Experimental
112
+ A view generator has been added.
113
+
114
+ 1.Generate a controller
115
+ 2.Add at least an index route for the controller
116
+ 3.rails g repack:view name_of_view (should be singular and match controller)
117
+
118
+
119
+ ## Contributing
120
+
121
+ Pull requests & issues welcome. Advice & criticism regarding webpack config approach also welcome.
122
+
123
+ Please ensure that pull requests pass both rubocop & rspec. New functionality should be discussed in an issue first.
124
+
125
+ ## Acknowledgements
126
+
127
+ * mipearson for his [webpack-rails](https://github.com/mipearson/webpack-rails) gem which inspired this implementation
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 = 'WebpackRails'
17
+ rdoc.options << '--line-numbers'
18
+ rdoc.rdoc_files.include('README.md')
19
+ rdoc.rdoc_files.include('lib/**/*.rb')
20
+ end
21
+
22
+ Bundler::GemHelper.install_tasks
23
+
24
+ task default: [:rubocop, :spec]
data/example/Procfile ADDED
@@ -0,0 +1,4 @@
1
+ # Run Rails & Webpack concurrently
2
+ # Example file from webpack-rails gem
3
+ rails: bundle exec rails server
4
+ webpack: ./node_modules/.bin/webpack-dev-server --config config/webpack.config.js
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+
3
+ const App = () => (
4
+ <div>
5
+ Hello World
6
+ </div>
7
+ )
8
+
9
+ export default App;
10
+
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import App from './containers/App';
4
+
5
+ ReactDOM.render(
6
+ <App />,
7
+ document.getElementById('app')
8
+ );
9
+
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import store from './store';
4
+ import { Provider } from 'react-redux';
5
+ import App from './containers/App';
6
+
7
+ ReactDOM.render(
8
+ <Provider store={store}>
9
+ <App />
10
+ </Provider>,
11
+ document.getElementById('app')
12
+ );
13
+
@@ -0,0 +1,8 @@
1
+ import { combineReducers } from 'redux';
2
+
3
+ const rootReducer = combineReducers({
4
+ //Add reducers here
5
+ });
6
+
7
+ export default rootReducer;
8
+
@@ -0,0 +1,23 @@
1
+ import { createStore, compose, applyMiddleware } from 'redux';
2
+ import thunk from 'redux-thunk';
3
+
4
+ // import the root reducer
5
+ import rootReducer from './reducers/index';
6
+
7
+ const createStoreWithMiddleware = compose (
8
+ applyMiddleware(thunk),
9
+ window.devToolsExtension ? window.devToolsExtension() : f => f
10
+ )(createStore)
11
+
12
+ const store = createStoreWithMiddleware(rootReducer);
13
+
14
+
15
+ if(module.hot) {
16
+ module.hot.accept('./reducers/',() => {
17
+ const nextRootReducer = require('./reducers/index').default;
18
+ store.replaceReducer(nextRootReducer);
19
+ });
20
+ }
21
+
22
+ export default store;
23
+
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+
3
+ const App = ({ children }) => (
4
+ <div>
5
+ Hello World
6
+ { children }
7
+ </div>
8
+ )
9
+
10
+ export default App;
11
+
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ const NoMatch = () => (
4
+ <div>404</div>
5
+ )
6
+
7
+ export default NoMatch;
8
+
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { Router, browserHistory } from 'react-router';
4
+ import routes from './routes';
5
+
6
+ ReactDOM.render(
7
+ <Router history={browserHistory} routes={routes} />,
8
+ document.getElementById('app')
9
+ );
10
+
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import { Router } from 'react-router';
4
+ import routes from './routes';
5
+ import { Provider } from 'react-redux';
6
+ import store, { history } from './store';
7
+
8
+ ReactDOM.render(
9
+ <Provider store={store}>
10
+ <Router history={history} routes={routes} />
11
+ </Provider>,
12
+ document.getElementById('app')
13
+ );
14
+
@@ -0,0 +1,7 @@
1
+ import { combineReducers } from 'redux';
2
+ import { routerReducer } from 'react-router-redux';
3
+
4
+ const rootReducer = combineReducers({ routing: routerReducer });
5
+
6
+ export default rootReducer;
7
+
@@ -0,0 +1,25 @@
1
+ import { createStore, compose, applyMiddleware } from 'redux';
2
+ import { syncHistoryWithStore } from 'react-router-redux';
3
+ import { browserHistory } from 'react-router';
4
+ import thunk from 'redux-thunk';
5
+
6
+ import rootReducer from './reducers/index';
7
+
8
+ const enhancers = compose(
9
+ applyMiddleware(thunk),
10
+ window.devToolsExtension ? window.devToolsExtension() : f => f
11
+ )
12
+
13
+ const store = createStore(rootReducer, {}, enhancers)
14
+
15
+ if(module.hot) {
16
+ module.hot.accept('./reducers/',() => {
17
+ const nextRootReducer = require('./reducers/index').default;
18
+ store.replaceReducer(nextRootReducer);
19
+ });
20
+ }
21
+
22
+ export const history = syncHistoryWithStore(browserHistory, store)
23
+
24
+ export default store
25
+
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { Route } from 'react-router';
3
+ import App from './containers/App';
4
+ import NoMatch from './components/NoMatch';
5
+
6
+ export default (
7
+ <Route>
8
+ <Route path="/" component={App} />
9
+ <Route path="*" status={404} component={NoMatch}/>
10
+ </Route>
11
+ )
12
+
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+
3
+ const Placeholder = () => (
4
+ <div>
5
+ </div>
6
+ )
7
+
8
+ export default Placeholder;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import ReactDOM from 'react-dom';
3
+ import Placeholder from './containers/Placeholder';
4
+
5
+ ReactDOM.render(
6
+ <Placeholder />,
7
+ document.getElementById('react')
8
+ );
@@ -0,0 +1,5 @@
1
+ <% content_for(:body_attributes) do %>
2
+ data-no-turbolink="true"
3
+ <% end %>
4
+ <div id="react"></div>
5
+ <%= javascript_include_tag *webpack_asset_paths('placeholder') %>
@@ -0,0 +1,12 @@
1
+
2
+ # Ignore bundler config.
3
+ /.bundle
4
+
5
+ # Ignore all logfiles and tempfiles.
6
+ /log/*
7
+ !/log/.keep
8
+ /tmp
9
+
10
+ # Don't commit node_modules (vendored npm bits) or built assets
11
+ /node_modules
12
+ /public/webpack
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "repack",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "scripts": {
6
+ "dev_server": "./node_modules/.bin/webpack-dev-server --config config/webpack.config.js",
7
+ "build": "webpack --config=config/webpack.config.js -p",
8
+ "heroku-setup": "heroku buildpacks:clear && heroku buildpacks:set heroku/nodejs && heroku buildpacks:add heroku/ruby --index 2",
9
+ "webpack:deploy-heroku": "webpack --config=config/webpack.config.heroku.js -p",
10
+ "heroku-postbuild": "npm run webpack:deploy-heroku"
11
+ },
12
+ "dependencies": {
13
+ "react": "^15.1.0",
14
+ "react-dom": "^15.1.0",
15
+ "stats-webpack-plugin": "^0.2.1",
16
+ "webpack": "^1.9.11",
17
+ "babel-core": "^6.9.1",
18
+ "babel-loader": "^6.2.4",
19
+ "babel-preset-es2015": "^6.9.0",
20
+ "babel-preset-react": "^6.5.0",
21
+ "babel-preset-stage-0": "^6.5.0",
22
+ "webpack-dev-middleware": "1.7.0"
23
+ },
24
+ "devDependencies": {
25
+ "webpack-dev-server": "^1.9.0"
26
+ }
27
+ }
@@ -0,0 +1,88 @@
1
+ // Example webpack configuration with asset fingerprinting in production.
2
+ 'use strict';
3
+
4
+ var path = require('path');
5
+ var webpack = require('webpack');
6
+ var StatsPlugin = require('stats-webpack-plugin');
7
+
8
+ // must match config.webpack.dev_server.port
9
+ var devServerPort = 3808;
10
+
11
+ // set TARGET=production on the environment to add asset fingerprints
12
+ var production = process.env.NODE_ENV === 'production';
13
+
14
+ var config = {
15
+ entry: {
16
+ // Sources are expected to live in $app_root/webpack
17
+ 'application': './client/application.js'
18
+ },
19
+
20
+ output: {
21
+ // Build assets directly in to public/webpack/, let webpack know
22
+ // that all webpacked assets start with webpack/
23
+
24
+ // must match config.webpack.output_dir
25
+ path: path.join(__dirname, '..', 'public', 'client'),
26
+ publicPath: '/client/',
27
+
28
+ filename: production ? '[name]-[chunkhash].js' : '[name].js'
29
+ },
30
+
31
+ resolve: {
32
+ root: path.join(__dirname, '..', 'client'),
33
+ extensions: ["", ".js", ".jsx", ".es6"]
34
+ },
35
+
36
+ module: {
37
+ loaders: [
38
+ {
39
+ test: /\.jsx?$/, // Match both .js and .jsx files
40
+ exclude: /node_modules/,
41
+ loader: "babel",
42
+ query:
43
+ {
44
+ presets:['es2015', 'react', 'stage-0']
45
+ }
46
+ },
47
+ {
48
+ test: /\.(jpe?g|png|gif|svg)$/i,
49
+ loaders: [
50
+ 'file?hash=sha512&digest=hex&name=[hash].[ext]',
51
+ 'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
52
+ ]
53
+ }
54
+ ]
55
+ },
56
+
57
+ plugins: [
58
+ // must match config.webpack.manifest_filename
59
+ new StatsPlugin('manifest.json', {
60
+ // We only need assetsByChunkName
61
+ chunkModules: false,
62
+ source: false,
63
+ chunks: false,
64
+ modules: false,
65
+ assets: true
66
+ })]
67
+ };
68
+
69
+ if (production) {
70
+ config.plugins.push(
71
+ new webpack.NoErrorsPlugin(),
72
+ new webpack.DefinePlugin({
73
+ 'process.env': { NODE_ENV: JSON.stringify('production') }
74
+ }),
75
+ new webpack.optimize.DedupePlugin(),
76
+ new webpack.optimize.OccurenceOrderPlugin()
77
+ );
78
+ } else {
79
+ config.devServer = {
80
+ port: devServerPort,
81
+ headers: { 'Access-Control-Allow-Origin': '*' }
82
+ };
83
+ config.output.publicPath = '//localhost:' + devServerPort + '/client/';
84
+ // Source maps
85
+ config.devtool = 'cheap-module-eval-source-map';
86
+ }
87
+
88
+ module.exports = config;
@@ -0,0 +1,92 @@
1
+ // Example webpack configuration with asset fingerprinting in production.
2
+ 'use strict';
3
+
4
+ var path = require('path');
5
+ var webpack = require('webpack');
6
+ var StatsPlugin = require('stats-webpack-plugin');
7
+
8
+ // must match config.webpack.dev_server.port
9
+ var devServerPort = 3808;
10
+
11
+ // set TARGET=production on the environment to add asset fingerprints
12
+ var production = process.env.TARGET === 'production';
13
+
14
+ var config = {
15
+ entry: {
16
+ // Sources are expected to live in $app_root/webpack
17
+ 'application': './client/application.js'
18
+ },
19
+
20
+ output: {
21
+ // Build assets directly in to public/webpack/, let webpack know
22
+ // that all webpacked assets start with webpack/
23
+
24
+ // must match config.webpack.output_dir
25
+ path: path.join(__dirname, '..', 'public', 'client'),
26
+ publicPath: '/client/',
27
+
28
+ filename: production ? '[name]-[chunkhash].js' : '[name].js'
29
+ },
30
+
31
+ resolve: {
32
+ root: path.join(__dirname, '..', 'client'),
33
+ extensions: ["", ".js", ".jsx", ".es6"]
34
+ },
35
+
36
+ module: {
37
+ loaders: [
38
+ {
39
+ test: /\.jsx?$/, // Match both .js and .jsx files
40
+ exclude: /node_modules/,
41
+ loader: "babel",
42
+ query:
43
+ {
44
+ presets:['es2015', 'react', 'stage-0']
45
+ }
46
+ },
47
+ {
48
+ test: /\.(jpe?g|png|gif|svg)$/i,
49
+ loaders: [
50
+ 'file?hash=sha512&digest=hex&name=[hash].[ext]',
51
+ 'image-webpack?bypassOnDebug&optimizationLevel=7&interlaced=false'
52
+ ]
53
+ }
54
+ ]
55
+ },
56
+
57
+ plugins: [
58
+ // must match config.webpack.manifest_filename
59
+ new StatsPlugin('manifest.json', {
60
+ // We only need assetsByChunkName
61
+ chunkModules: false,
62
+ source: false,
63
+ chunks: false,
64
+ modules: false,
65
+ assets: true
66
+ })]
67
+ };
68
+
69
+ if (production) {
70
+ config.plugins.push(
71
+ new webpack.NoErrorsPlugin(),
72
+ new webpack.optimize.UglifyJsPlugin({
73
+ compressor: { warnings: false },
74
+ sourceMap: false
75
+ }),
76
+ new webpack.DefinePlugin({
77
+ 'process.env': { NODE_ENV: JSON.stringify('production') }
78
+ }),
79
+ new webpack.optimize.DedupePlugin(),
80
+ new webpack.optimize.OccurenceOrderPlugin()
81
+ );
82
+ } else {
83
+ config.devServer = {
84
+ port: devServerPort,
85
+ headers: { 'Access-Control-Allow-Origin': '*' }
86
+ };
87
+ config.output.publicPath = '//localhost:' + devServerPort + '/client/';
88
+ // Source maps
89
+ config.devtool = 'cheap-module-eval-source-map';
90
+ }
91
+
92
+ module.exports = config;
@@ -0,0 +1,136 @@
1
+ module Repack
2
+ # :nodoc:
3
+ class InstallGenerator < ::Rails::Generators::Base
4
+ source_root File.expand_path("../../../../example", __FILE__)
5
+
6
+ desc "Install everything you need for a basic webpack-rails integration"
7
+ class_option :router, type: :boolean, default: false, description: 'Add React Router'
8
+ class_option :redux, type: :boolean, default: false, description: 'Add Redux'
9
+
10
+ def copy_package_json
11
+ copy_file "package.json", "package.json"
12
+
13
+ if options[:router]
14
+ insert_into_file './package.json', after: /dependencies\": {\n/ do
15
+ <<-'RUBY'
16
+ "react-router": "^2.4.1",
17
+ RUBY
18
+ end
19
+ end
20
+
21
+ if options[:redux]
22
+ insert_into_file './package.json', after: /dependencies\": {\n/ do
23
+ <<-'RUBY'
24
+ "react-redux": "^4.4.5",
25
+ "redux": "^3.5.2",
26
+ "redux-thunk": "^2.1.0",
27
+ RUBY
28
+ end
29
+ end
30
+
31
+ if options[:router] && options[:redux]
32
+ insert_into_file './package.json', after: /dependencies\": {\n/ do
33
+ <<-'RUBY'
34
+ "react-router-redux": "^4.0.5",
35
+ RUBY
36
+ end
37
+ end
38
+ end
39
+
40
+ def copy_webpack_conf
41
+ copy_file "webpack.config.js", "config/webpack.config.js"
42
+ copy_file "webpack.config.heroku.js", "config/webpack.config.heroku.js"
43
+ end
44
+
45
+ def create_webpack_application_js
46
+ empty_directory "client"
47
+ empty_directory "client/containers"
48
+ empty_directory "client/components"
49
+
50
+ if options[:router] && options[:redux]
51
+ copy_file "boilerplate/router_redux/application.js", "client/application.js"
52
+ copy_file "boilerplate/routes.js", "client/routes.js"
53
+ copy_file "boilerplate/router_redux/store.js", "client/store.js"
54
+ copy_file "boilerplate/router_redux/reducers.js", "client/reducers/index.js"
55
+ create_file "client/actions.js"
56
+ copy_file "boilerplate/router/App.js", "client/containers/App.js"
57
+ copy_file "boilerplate/router/NoMatch.js", "client/components/NoMatch.js"
58
+ elsif options[:router]
59
+ copy_file "boilerplate/router/application.js", "client/application.js"
60
+ copy_file "boilerplate/routes.js", "client/routes.js"
61
+ copy_file "boilerplate/router/App.js", "client/containers/App.js"
62
+ copy_file "boilerplate/router/NoMatch.js", "client/components/NoMatch.js"
63
+ elsif options[:redux]
64
+ copy_file "boilerplate/redux/application.js", "client/application.js"
65
+ copy_file "boilerplate/redux/store.js", "client/store.js"
66
+ copy_file "boilerplate/redux/reducers.js", "client/reducers/index.js"
67
+ create_file "client/actions.js"
68
+ copy_file "boilerplate/App.js", "client/containers/App.js"
69
+ else
70
+ copy_file "boilerplate/application.js", "client/application.js"
71
+ copy_file "boilerplate/App.js", "client/containers/App.js"
72
+ end
73
+
74
+ application_view = 'app/views/layouts/application.html.erb'
75
+
76
+ if File.exists? application_view
77
+ insert_into_file 'app/views/layouts/application.html.erb', before: /<\/body>/ do
78
+ <<-'RUBY'
79
+ <%= javascript_include_tag *webpack_asset_paths('application') %>
80
+ RUBY
81
+ end
82
+ insert_into_file 'app/views/layouts/application.html.erb', before: /<\/head>/ do
83
+ <<-'RUBY'
84
+ <% if Rails.env.development? %>
85
+ <script src="http://localhost:3808/webpack-dev-server.js"></script>
86
+ <% end %>
87
+ RUBY
88
+ end
89
+ else
90
+ puts "\n\n***WARNING*** HAML NOT SUPPORTED IN applictaion.html additional steps required\n\n"
91
+ end
92
+ end
93
+
94
+ def add_to_gitignore
95
+ append_to_file ".gitignore" do
96
+ <<-EOF.strip_heredoc
97
+ # Added by repack
98
+ /node_modules
99
+ /public/webpack
100
+ EOF
101
+ end
102
+ end
103
+
104
+ def run_npm_install
105
+ run "npm install" if yes?("Would you like us to run 'npm install' for you?")
106
+ end
107
+
108
+ def whats_next
109
+ puts <<-EOF.strip_heredoc
110
+
111
+ We've set up the basics of repack for you, but you'll still
112
+ need to:
113
+
114
+ 1. Add an element with an id of 'app' to your layout
115
+ 2. To disable hot module replacement remove <script src="http://localhost:3808/webpack-dev-server.js"></script> from layout
116
+ 3. Run 'npm run dev_server' to run the webpack-dev-server
117
+ 4. Run 'bundle exec rails s' to run the rails server (both servers must be running)
118
+ 5. If you are using react-router and want to sync server routes add:
119
+ get '*unmatched_route', to: <your client controller>#<default action>
120
+ This must be the very last route in your routes.rb file
121
+ e.g. get '*unmatched_route', to: 'home#index'
122
+
123
+ FOR HEROKU DEPLOYS:
124
+ 1. npm run heroku-setup
125
+ 2. Push to heroku the post-build hook will take care of the rest
126
+
127
+ See the README.md for this gem at
128
+ https://github.com/cottonwoodcoding/repack/blob/master/README.md
129
+ for more info.
130
+
131
+ Thanks for using repack!
132
+
133
+ EOF
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,45 @@
1
+ module Repack
2
+ # :nodoc:
3
+ class ViewGenerator < ::Rails::Generators::Base
4
+ source_root File.expand_path("../../../../example", __FILE__)
5
+
6
+ desc "Generate a view with webpack entry / rails view / and react container"
7
+
8
+ def normalize_view_name
9
+ raise "View name argument missing" if args.length == 0
10
+ @view = args[0]
11
+ end
12
+
13
+ def update_webpack_entry
14
+ name = @view.downcase.gsub(/ /, "_")
15
+ path = "'#{name}': './client/#{name}.js',"
16
+ insert_into_file 'config/webpack.config.js', after: /entry: {\n/ do
17
+ <<-CONFIG
18
+ #{path}
19
+ CONFIG
20
+ end
21
+ end
22
+
23
+ def create_entry_file
24
+ file = "client/#{@view.gsub(/ /, '')}.js"
25
+ name = @view.titleize.gsub(/ /, '')
26
+ copy_file "boilerplate/views/ViewTemplate.js", file
27
+ gsub_file file, /Placeholder/, name
28
+ end
29
+
30
+ def create_container
31
+ name = @view.titleize.gsub(/ /, '')
32
+ file = "client/containers/#{name}.js"
33
+ copy_file "boilerplate/views/ContainerTemplate.js", file
34
+ gsub_file file, /Placeholder/, name
35
+ end
36
+
37
+ def create_rails_view
38
+ name = @view.downcase.gsub(/ /, '_')
39
+ empty_directory "app/views/#{name.pluralize}"
40
+ file = "app/views/#{name.pluralize}/index.html.erb"
41
+ copy_file "boilerplate/views/rails_view.html.erb", file
42
+ gsub_file file, /placeholder/, name
43
+ end
44
+ end
45
+ end
data/lib/repack.rb ADDED
@@ -0,0 +1 @@
1
+ require 'webpack/rails'
@@ -0,0 +1,19 @@
1
+ namespace :webpack do
2
+ desc "Compile webpack bundles"
3
+ task compile: :environment do
4
+ ENV["TARGET"] = 'production'
5
+ webpack_bin = ::Rails.root.join(::Rails.configuration.webpack.binary)
6
+ config_file = ::Rails.root.join(::Rails.configuration.webpack.config_file)
7
+
8
+ unless File.exist?(webpack_bin)
9
+ raise "Can't find our webpack executable at #{webpack_bin} - have you run `npm install`?"
10
+ end
11
+
12
+ unless File.exist?(config_file)
13
+ raise "Can't find our webpack config file at #{config_file}"
14
+ end
15
+
16
+ result = `#{webpack_bin} --bail --config #{config_file} 2>&1`
17
+ raise result unless $? == 0
18
+ end
19
+ end
@@ -0,0 +1,2 @@
1
+ require 'webpack/rails/react/version'
2
+ require 'webpack/railtie' if defined? ::Rails::Railtie
@@ -0,0 +1,36 @@
1
+ require 'action_view'
2
+ require 'webpack/rails/react/manifest'
3
+
4
+ module Webpack
5
+ module Rails
6
+ module React
7
+ # Asset path helpers for use with webpack
8
+ module Helper
9
+ # Return asset paths for a particular webpack entry point.
10
+ #
11
+ # Response may either be full URLs (eg http://localhost/...) if the dev server
12
+ # is in use or a host-relative URl (eg /webpack/...) if assets are precompiled.
13
+ #
14
+ # Will raise an error if our manifest can't be found or the entry point does
15
+ # not exist.
16
+ def webpack_asset_paths(source, extension: nil)
17
+ return "" unless source.present?
18
+
19
+ paths = Webpack::Rails::React::Manifest.asset_paths(source)
20
+ paths = paths.select {|p| p.ends_with? ".#{extension}" } if extension
21
+
22
+ host = ::Rails.configuration.webpack.dev_server.host
23
+ port = ::Rails.configuration.webpack.dev_server.port
24
+
25
+ if ::Rails.configuration.webpack.dev_server.enabled
26
+ paths.map! do |p|
27
+ "//#{host}:#{port}#{p}"
28
+ end
29
+ end
30
+
31
+ paths
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,91 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+
4
+ module Webpack
5
+ module Rails
6
+ module React
7
+ # Webpack manifest loading, caching & entry point retrieval
8
+ class Manifest
9
+ # Raised if we can't read our webpack manifest for whatever reason
10
+ class ManifestLoadError < StandardError
11
+ def initialize(message, orig)
12
+ super "#{message} (original error #{orig})"
13
+ end
14
+ end
15
+
16
+ # Raised if a supplied entry point does not exist in the webpack manifest
17
+ class EntryPointMissingError < StandardError
18
+ end
19
+
20
+ class << self
21
+ # :nodoc:
22
+ def asset_paths(source)
23
+ paths = manifest["assetsByChunkName"][source]
24
+ if paths
25
+ # Can be either a string or an array of strings.
26
+ # Do not include source maps as they are not javascript
27
+ [paths].flatten.reject { |p| p =~ /.*\.map$/ }.map do |p|
28
+ "/#{::Rails.configuration.webpack.public_path}/#{p}"
29
+ end
30
+ else
31
+ raise EntryPointMissingError, "Can't find entry point '#{source}' in webpack manifest"
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def manifest
38
+ if ::Rails.configuration.webpack.dev_server.enabled
39
+ # Don't cache if we're in dev server mode, manifest may change ...
40
+ load_manifest
41
+ else
42
+ # ... otherwise cache at class level, as JSON loading/parsing can be expensive
43
+ @manifest ||= load_manifest
44
+ end
45
+ end
46
+
47
+ def load_manifest
48
+ data = if ::Rails.configuration.webpack.dev_server.enabled
49
+ load_dev_server_manifest
50
+ else
51
+ load_static_manifest
52
+ end
53
+ JSON.parse(data)
54
+ end
55
+
56
+ def load_dev_server_manifest
57
+ http = Net::HTTP.new(
58
+ "localhost",
59
+ ::Rails.configuration.webpack.dev_server.port)
60
+ http.use_ssl = ::Rails.configuration.webpack.dev_server.https
61
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
62
+ http.get(dev_server_path).body
63
+ rescue => e
64
+ raise ManifestLoadError.new("Could not load manifest from webpack-dev-server at #{dev_server_url} - is it running, and is stats-webpack-plugin loaded?", e)
65
+ end
66
+
67
+ def load_static_manifest
68
+ File.read(static_manifest_path)
69
+ rescue => e
70
+ raise ManifestLoadError.new("Could not load compiled manifest from #{static_manifest_path} - have you run `rake webpack:compile`?", e)
71
+ end
72
+
73
+ def static_manifest_path
74
+ ::Rails.root.join(
75
+ ::Rails.configuration.webpack.output_dir,
76
+ ::Rails.configuration.webpack.manifest_filename
77
+ )
78
+ end
79
+
80
+ def dev_server_path
81
+ "/#{::Rails.configuration.webpack.public_path}/#{::Rails.configuration.webpack.manifest_filename}"
82
+ end
83
+
84
+ def dev_server_url
85
+ "http://localhost:#{::Rails.configuration.webpack.dev_server.port}#{dev_server_path}"
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,8 @@
1
+ module Webpack
2
+ # :nodoc:
3
+ module Rails
4
+ module React
5
+ VERSION = "2.0.0"
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ require 'rails'
2
+ require 'rails/railtie'
3
+ require 'webpack/rails/react/helper'
4
+
5
+ module Webpack
6
+ # :nodoc:
7
+ class Railtie < ::Rails::Railtie
8
+ config.after_initialize do
9
+ ActiveSupport.on_load(:action_view) do
10
+ include Webpack::Rails::React::Helper
11
+ end
12
+ end
13
+
14
+ config.webpack = ActiveSupport::OrderedOptions.new
15
+ config.webpack.config_file = 'config/webpack.config.js'
16
+ config.webpack.binary = 'node_modules/.bin/webpack'
17
+
18
+ config.webpack.dev_server = ActiveSupport::OrderedOptions.new
19
+ config.webpack.dev_server.host = 'localhost'
20
+ config.webpack.dev_server.port = 3808
21
+ config.webpack.dev_server.https = false # note - this will use OpenSSL::SSL::VERIFY_NONE
22
+ config.webpack.dev_server.binary = 'node_modules/.bin/webpack-dev-server'
23
+ config.webpack.dev_server.enabled = !::Rails.env.production?
24
+
25
+ config.webpack.output_dir = "public/client"
26
+ config.webpack.public_path = "client"
27
+ config.webpack.manifest_filename = "manifest.json"
28
+
29
+ rake_tasks do
30
+ load "tasks/webpack.rake"
31
+ end
32
+ end
33
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: repack
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Dave Jungst
8
+ - Jake Sorce
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2016-10-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 3.2.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 3.2.0
28
+ description: Production-tested, JavaScript-first tooling to use webpack within your
29
+ Rails application
30
+ email:
31
+ - dave@cottonwoodcoding.com
32
+ - jake@cottonwoodcoding.com
33
+ executables: []
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - MIT-LICENSE
38
+ - README.md
39
+ - Rakefile
40
+ - example/Procfile
41
+ - example/boilerplate/App.js
42
+ - example/boilerplate/application.js
43
+ - example/boilerplate/redux/application.js
44
+ - example/boilerplate/redux/reducers.js
45
+ - example/boilerplate/redux/store.js
46
+ - example/boilerplate/router/App.js
47
+ - example/boilerplate/router/NoMatch.js
48
+ - example/boilerplate/router/application.js
49
+ - example/boilerplate/router_redux/application.js
50
+ - example/boilerplate/router_redux/reducers.js
51
+ - example/boilerplate/router_redux/store.js
52
+ - example/boilerplate/routes.js
53
+ - example/boilerplate/views/ContainerTemplate.js
54
+ - example/boilerplate/views/ViewTemplate.js
55
+ - example/boilerplate/views/rails_view.html.erb
56
+ - example/dot_gitignore
57
+ - example/package.json
58
+ - example/webpack.config.heroku.js
59
+ - example/webpack.config.js
60
+ - lib/generators/repack/install_generator.rb
61
+ - lib/generators/repack/view_generator.rb
62
+ - lib/repack.rb
63
+ - lib/tasks/webpack.rake
64
+ - lib/webpack/rails.rb
65
+ - lib/webpack/rails/react/helper.rb
66
+ - lib/webpack/rails/react/manifest.rb
67
+ - lib/webpack/rails/react/version.rb
68
+ - lib/webpack/railtie.rb
69
+ homepage: https://github.com/cottonwoodcoding/reapack
70
+ licenses:
71
+ - MIT
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: 2.0.0
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 2.5.1
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: Webpack / Rails / React
93
+ test_files: []