Merge pull request #740 from okriuchykhin/ok_SCI_1461

Add Webpacker and React [SCI-1461]
This commit is contained in:
okriuchykhin 2017-07-13 14:32:34 +02:00 committed by GitHub
commit d671ad50b5
27 changed files with 5869 additions and 5 deletions

31
.babelrc Normal file
View file

@ -0,0 +1,31 @@
{
"presets": [
[
"env",
{
"modules": false,
"targets": {
"browsers": "> 1%",
"uglify": true
},
"useBuiltIns": true
}
],
"react",
"es2015"
],
"plugins": [
"syntax-dynamic-import",
[
"transform-class-properties",
{
"spec": true
}
]
],
"env": {
"test": {
"plugins": ["transform-es2015-modules-commonjs"]
}
}
}

View file

@ -1,8 +1,21 @@
{
"extends": "google",
"env": {
"browser": true,
"jquery": true
"jquery": true,
"es6": true,
"node": true
},
"plugins": [
"react"
],
"extends": ["eslint:recommended", "plugin:react/recommended"],
"parserOptions": {
"sourceType": "module",
"ecmaVersion": 6,
"ecmaFeatures": {
"impliedStrict": true,
"jsx": true
}
},
"rules": {
"spaced-comment": [

4
.gitignore vendored
View file

@ -53,3 +53,7 @@ rubocop_cache
# Ignore ESLint local instalation
node_modules
# Added during webpacker install
/public/packs
/node_modules

4
.postcssrc.yml Normal file
View file

@ -0,0 +1,4 @@
plugins:
postcss-smart-import: {}
precss: {}
autoprefixer: {}

View file

@ -2,7 +2,8 @@ FROM ruby:2.4.1
MAINTAINER BioSistemika <info@biosistemika.com>
# additional dependecies
RUN apt-get update -qq && \
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
nodejs \
postgresql-client \
@ -10,6 +11,7 @@ RUN apt-get update -qq && \
unison \
sudo graphviz --no-install-recommends \
libfile-mimeinfo-perl && \
npm install -g yarn && \
rm -rf /var/lib/apt/lists/*
# heroku tools

View file

@ -2,7 +2,8 @@ FROM ruby:2.4.1
MAINTAINER BioSistemika <info@biosistemika.com>
# additional dependecies
RUN apt-get update -qq && \
RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - && \
apt-get update -qq && \
apt-get install -y \
nodejs \
postgresql-client \
@ -10,6 +11,7 @@ RUN apt-get update -qq && \
default-jre-headless \
sudo graphviz --no-install-recommends \
libfile-mimeinfo-perl && \
npm install -g yarn && \
rm -rf /var/lib/apt/lists/*
ENV RAILS_ENV production

View file

@ -3,6 +3,7 @@ source 'http://rubygems.org'
ruby '2.4.1'
gem 'rails', '5.1.1'
gem 'webpacker', '~> 2.0'
gem 'figaro'
gem 'pg'
gem 'devise', '~> 4.3.0'

View file

@ -360,6 +360,10 @@ GEM
unicode-display_width (1.3.0)
warden (1.2.7)
rack (>= 1.0)
webpacker (2.0)
activesupport (>= 4.2)
multi_json (~> 1.2)
railties (>= 4.2)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
@ -445,6 +449,7 @@ DEPENDENCIES
tzinfo-data
uglifier (>= 1.3.0)
underscore-rails
webpacker (~> 2.0)
wicked_pdf
wkhtmltopdf-heroku
yomu

View file

@ -0,0 +1,10 @@
/* eslint no-console:0 */
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
//
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
// layout file, like app/views/layouts/application.html.erb
console.log('Hello World from Webpacker')

View file

@ -0,0 +1,26 @@
// Run this example by adding <%= javascript_pack_tag 'hello_react' %> to the head of your layout file,
// like app/views/layouts/application.html.erb. All it does is render <div>Hello React</div> at the bottom
// of the page.
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
const Hello = props => (
<div>Hello {props.name}!</div>
)
Hello.defaultProps = {
name: 'David'
}
Hello.propTypes = {
name: PropTypes.string
}
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.render(
<Hello name="React" />,
document.body.appendChild(document.createElement('div'))
)
})

28
bin/webpack Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env ruby
$stdout.sync = true
require "shellwords"
require "yaml"
ENV["RAILS_ENV"] ||= "development"
RAILS_ENV = ENV["RAILS_ENV"]
ENV["NODE_ENV"] ||= RAILS_ENV
NODE_ENV = ENV["NODE_ENV"]
APP_PATH = File.expand_path("../", __dir__)
NODE_MODULES_PATH = File.join(APP_PATH, "node_modules")
WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/#{NODE_ENV}.js")
unless File.exist?(WEBPACK_CONFIG)
puts "Webpack configuration not found."
puts "Please run bundle exec rails webpacker:install to install webpacker"
exit!
end
newenv = { "NODE_PATH" => NODE_MODULES_PATH.shellescape }
cmdline = ["yarn", "run", "webpack", "--", "--config", WEBPACK_CONFIG] + ARGV
Dir.chdir(APP_PATH) do
exec newenv, *cmdline
end

43
bin/webpack-dev-server Executable file
View file

@ -0,0 +1,43 @@
#!/usr/bin/env ruby
$stdout.sync = true
require "shellwords"
require "yaml"
ENV["RAILS_ENV"] ||= "development"
RAILS_ENV = ENV["RAILS_ENV"]
ENV["NODE_ENV"] ||= RAILS_ENV
NODE_ENV = ENV["NODE_ENV"]
APP_PATH = File.expand_path("../", __dir__)
CONFIG_FILE = File.join(APP_PATH, "config/webpacker.yml")
NODE_MODULES_PATH = File.join(APP_PATH, "node_modules")
WEBPACK_CONFIG = File.join(APP_PATH, "config/webpack/development.js")
def args(key)
index = ARGV.index(key)
index ? ARGV[index + 1] : nil
end
begin
dev_server = YAML.load_file(CONFIG_FILE)["development"]["dev_server"]
DEV_SERVER_HOST = "http#{"s" if args('--https') || dev_server["https"]}://#{args('--host') || dev_server["host"]}:#{args('--port') || dev_server["port"]}"
rescue Errno::ENOENT, NoMethodError
puts "Webpack dev_server configuration not found in #{CONFIG_FILE}."
puts "Please run bundle exec rails webpacker:install to install webpacker"
exit!
end
newenv = {
"NODE_PATH" => NODE_MODULES_PATH.shellescape,
"ASSET_HOST" => DEV_SERVER_HOST.shellescape
}.freeze
cmdline = ["yarn", "run", "webpack-dev-server", "--", "--progress", "--color", "--config", WEBPACK_CONFIG] + ARGV
Dir.chdir(APP_PATH) do
exec newenv, *cmdline
end

View file

@ -0,0 +1,35 @@
// Common configuration for webpacker loaded from config/webpacker.yml
const { join, resolve } = require('path')
const { env } = require('process')
const { safeLoad } = require('js-yaml')
const { readFileSync } = require('fs')
const configPath = resolve('config', 'webpacker.yml')
const loadersDir = join(__dirname, 'loaders')
const settings = safeLoad(readFileSync(configPath), 'utf8')[env.NODE_ENV]
function removeOuterSlashes(string) {
return string.replace(/^\/*/, '').replace(/\/*$/, '')
}
function formatPublicPath(host = '', path = '') {
let formattedHost = removeOuterSlashes(host)
if (formattedHost && !/^http/i.test(formattedHost)) {
formattedHost = `//${formattedHost}`
}
const formattedPath = removeOuterSlashes(path)
return `${formattedHost}/${formattedPath}/`
}
const output = {
path: resolve('public', settings.public_output_path),
publicPath: formatPublicPath(env.ASSET_HOST, settings.public_output_path)
}
module.exports = {
settings,
env,
loadersDir,
output
}

View file

@ -0,0 +1,32 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
const merge = require('webpack-merge')
const sharedConfig = require('./shared.js')
const { settings, output } = require('./configuration.js')
module.exports = merge(sharedConfig, {
devtool: 'cheap-eval-source-map',
stats: {
errorDetails: true
},
output: {
pathinfo: true
},
devServer: {
clientLogLevel: 'none',
https: settings.dev_server.https,
host: settings.dev_server.host,
port: settings.dev_server.port,
contentBase: output.path,
publicPath: output.publicPath,
compress: true,
headers: { 'Access-Control-Allow-Origin': '*' },
historyApiFallback: true,
watchOptions: {
ignored: /node_modules/
}
}
})

View file

@ -0,0 +1,12 @@
const { env, publicPath } = require('../configuration.js')
module.exports = {
test: /\.(jpg|jpeg|png|gif|svg|eot|ttf|woff|woff2)$/i,
use: [{
loader: 'file-loader',
options: {
publicPath,
name: env.NODE_ENV === 'production' ? '[name]-[hash].[ext]' : '[name].[ext]'
}
}]
}

View file

@ -0,0 +1,5 @@
module.exports = {
test: /\.js(\.erb)?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}

View file

@ -0,0 +1,4 @@
module.exports = {
test: /\.coffee(\.erb)?$/,
loader: 'coffee-loader'
}

View file

@ -0,0 +1,9 @@
module.exports = {
test: /\.erb$/,
enforce: 'pre',
exclude: /node_modules/,
loader: 'rails-erb-loader',
options: {
runner: 'bin/rails runner'
}
}

5
config/webpack/loaders/react.js vendored Normal file
View file

@ -0,0 +1,5 @@
module.exports = {
test: /\.(js|jsx)?(\.erb)?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}

View file

@ -0,0 +1,15 @@
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const { env } = require('../configuration.js')
module.exports = {
test: /\.(scss|sass|css)$/i,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } },
{ loader: 'postcss-loader', options: { sourceMap: true } },
'resolve-url-loader',
{ loader: 'sass-loader', options: { sourceMap: true } }
]
})
}

View file

@ -0,0 +1,35 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
/* eslint global-require: 0 */
const webpack = require('webpack')
const merge = require('webpack-merge')
const CompressionPlugin = require('compression-webpack-plugin')
const sharedConfig = require('./shared.js')
module.exports = merge(sharedConfig, {
output: { filename: '[name]-[chunkhash].js' },
devtool: 'source-map',
stats: 'normal',
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true,
sourceMap: true,
compress: {
warnings: false
},
output: {
comments: false
}
}),
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|css|html|json|ico|svg|eot|otf|ttf)$/
})
]
})

58
config/webpack/shared.js Normal file
View file

@ -0,0 +1,58 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
/* eslint global-require: 0 */
/* eslint import/no-dynamic-require: 0 */
const webpack = require('webpack')
const { basename, dirname, join, relative, resolve } = require('path')
const { sync } = require('glob')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const ManifestPlugin = require('webpack-manifest-plugin')
const extname = require('path-complete-extname')
const { env, settings, output, loadersDir } = require('./configuration.js')
const extensionGlob = `**/*{${settings.extensions.join(',')}}*`
const entryPath = join(settings.source_path, settings.source_entry_path)
const packPaths = sync(join(entryPath, extensionGlob))
module.exports = {
entry: packPaths.reduce(
(map, entry) => {
const localMap = map
const namespace = relative(join(entryPath), dirname(entry))
localMap[join(namespace, basename(entry, extname(entry)))] = resolve(entry)
return localMap
}, {}
),
output: {
filename: '[name].js',
path: output.path,
publicPath: output.publicPath
},
module: {
rules: sync(join(loadersDir, '*.js')).map(loader => require(loader))
},
plugins: [
new webpack.EnvironmentPlugin(JSON.parse(JSON.stringify(env))),
new ExtractTextPlugin(env.NODE_ENV === 'production' ? '[name]-[hash].css' : '[name].css'),
new ManifestPlugin({
publicPath: output.publicPath,
writeToFileEmit: true
})
],
resolve: {
extensions: settings.extensions,
modules: [
resolve(settings.source_path),
'node_modules'
]
},
resolveLoader: {
modules: ['node_modules']
}
}

6
config/webpack/test.js Normal file
View file

@ -0,0 +1,6 @@
// Note: You must restart bin/webpack-dev-server for changes to take effect
const merge = require('webpack-merge')
const sharedConfig = require('./shared.js')
module.exports = merge(sharedConfig, {})

38
config/webpacker.yml Normal file
View file

@ -0,0 +1,38 @@
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/javascript
source_entry_path: packs
public_output_path: packs
extensions:
- .coffee
- .erb
- .js
- .jsx
- .ts
- .vue
- .sass
- .scss
- .css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
dev_server:
host: 0.0.0.0
port: 8080
https: false
test:
<<: *default
public_output_path: packs-test
production:
<<: *default

View file

@ -29,6 +29,23 @@ services:
- scinote_development_bundler:/usr/local/bundle/
- scinote_development_files:/usr/src/app/public/system
webpack:
build:
context: .
dockerfile: Dockerfile
image: scinote_web_development
container_name: scinote_webpack_development
stdin_open: true
tty: true
ports:
- "8080:8080"
command: >
bash -c "./bin/webpack-dev-server"
environment:
- RAILS_ENV=development
volumes:
- .:/usr/src/app
volumes:
scinote_development_postgres:
scinote_development_bundler:

View file

@ -21,6 +21,41 @@
},
"devDependencies": {
"eslint": "^3.7.1",
"eslint-config-google": "^0.5.0"
"eslint-config-google": "^0.5.0",
"eslint-plugin-react": "^7.1.0",
"webpack-dev-server": "^2.5.1"
},
"dependencies": {
"autoprefixer": "^7.1.2",
"babel-core": "^6.25.0",
"babel-loader": "7.x",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"coffee-loader": "^0.7.3",
"coffee-script": "^1.12.6",
"compression-webpack-plugin": "^0.4.0",
"css-loader": "^0.28.4",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"glob": "^7.1.2",
"js-yaml": "^3.9.0",
"node-sass": "^4.5.3",
"path-complete-extname": "^0.1.0",
"postcss-loader": "^2.0.6",
"postcss-smart-import": "^0.7.5",
"precss": "^2.0.0",
"prop-types": "^15.5.10",
"rails-erb-loader": "^5.0.2",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"resolve-url-loader": "^2.1.0",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"webpack": "^3.2.0",
"webpack-manifest-plugin": "^1.1.2",
"webpack-merge": "^4.1.0"
}
}

5389
yarn.lock Normal file

File diff suppressed because it is too large Load diff