diff --git a/lib/install/angular.rb b/lib/install/angular.rb
new file mode 100644
index 000000000..ddf8e00be
--- /dev/null
+++ b/lib/install/angular.rb
@@ -0,0 +1,18 @@
+require "webpacker/configuration"
+
+puts "Copying angular loader to #{Webpacker::Configuration.config_path}/loaders"
+copy_file "#{__dir__}/config/loaders/installers/angular.js", "config/webpack/loaders/angular.js"
+
+puts "Copying angular example entry file to #{Webpacker::Configuration.entry_path}"
+copy_file "#{__dir__}/examples/angular/hello_angular.js", "#{Webpacker::Configuration.entry_path}/hello_angular.js"
+
+puts "Copying hello_angular app to #{Webpacker::Configuration.source_path}"
+directory "#{__dir__}/examples/angular/hello_angular", "#{Webpacker::Configuration.source_path}/hello_angular"
+
+puts "Copying tsconfig.json to the Rails root directory for typescript"
+copy_file "#{__dir__}/examples/angular/tsconfig.json", "tsconfig.json"
+
+puts "Installing all angular dependencies"
+run "./bin/yarn add typescript ts-loader core-js zone.js rxjs @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic"
+
+puts "Webpacker now supports angular.js and typescript 🎉"
diff --git a/lib/install/config/.postcssrc.yml b/lib/install/config/.postcssrc.yml
new file mode 100644
index 000000000..bc4f02ab3
--- /dev/null
+++ b/lib/install/config/.postcssrc.yml
@@ -0,0 +1,4 @@
+plugins:
+ postcss-smart-import: {}
+ precss: {}
+ autoprefixer: {}
diff --git a/lib/install/config/loaders/core/assets.js b/lib/install/config/loaders/core/assets.js
new file mode 100644
index 000000000..c859daf0b
--- /dev/null
+++ b/lib/install/config/loaders/core/assets.js
@@ -0,0 +1,12 @@
+const { env, publicPath } = require('../configuration.js')
+
+module.exports = {
+ test: /\.(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]'
+ }
+ }]
+}
diff --git a/lib/install/config/loaders/core/babel.js b/lib/install/config/loaders/core/babel.js
new file mode 100644
index 000000000..82481e15e
--- /dev/null
+++ b/lib/install/config/loaders/core/babel.js
@@ -0,0 +1,10 @@
+module.exports = {
+ test: /\.js(\.erb)?$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ ['env', { modules: false }]
+ ]
+ }
+}
diff --git a/lib/install/config/loaders/core/coffee.js b/lib/install/config/loaders/core/coffee.js
new file mode 100644
index 000000000..dae874249
--- /dev/null
+++ b/lib/install/config/loaders/core/coffee.js
@@ -0,0 +1,4 @@
+module.exports = {
+ test: /\.coffee(\.erb)?$/,
+ loader: 'coffee-loader'
+}
diff --git a/lib/install/config/loaders/core/erb.js b/lib/install/config/loaders/core/erb.js
new file mode 100644
index 000000000..c1a6cc158
--- /dev/null
+++ b/lib/install/config/loaders/core/erb.js
@@ -0,0 +1,9 @@
+module.exports = {
+ test: /\.erb$/,
+ enforce: 'pre',
+ exclude: /node_modules/,
+ loader: 'rails-erb-loader',
+ options: {
+ runner: 'DISABLE_SPRING=1 bin/rails runner'
+ }
+}
diff --git a/lib/install/config/loaders/core/sass.js b/lib/install/config/loaders/core/sass.js
new file mode 100644
index 000000000..faba9d5b0
--- /dev/null
+++ b/lib/install/config/loaders/core/sass.js
@@ -0,0 +1,9 @@
+const ExtractTextPlugin = require('extract-text-webpack-plugin')
+
+module.exports = {
+ test: /\.(scss|sass|css)$/i,
+ use: ExtractTextPlugin.extract({
+ fallback: 'style-loader',
+ use: ['css-loader', 'postcss-loader', 'sass-loader']
+ })
+}
diff --git a/lib/install/config/loaders/installers/angular.js b/lib/install/config/loaders/installers/angular.js
new file mode 100644
index 000000000..cbb916e33
--- /dev/null
+++ b/lib/install/config/loaders/installers/angular.js
@@ -0,0 +1,4 @@
+module.exports = {
+ test: /.ts$/,
+ loader: 'ts-loader'
+}
diff --git a/lib/install/config/loaders/installers/react.js b/lib/install/config/loaders/installers/react.js
new file mode 100644
index 000000000..065dc4e07
--- /dev/null
+++ b/lib/install/config/loaders/installers/react.js
@@ -0,0 +1,11 @@
+module.exports = {
+ test: /\.(js|jsx)?(\.erb)?$/,
+ exclude: /node_modules/,
+ loader: 'babel-loader',
+ options: {
+ presets: [
+ 'react',
+ ['env', { modules: false }]
+ ]
+ }
+}
diff --git a/lib/install/config/loaders/installers/vue.js b/lib/install/config/loaders/installers/vue.js
new file mode 100644
index 000000000..7dbab0409
--- /dev/null
+++ b/lib/install/config/loaders/installers/vue.js
@@ -0,0 +1,10 @@
+module.exports = {
+ test: /.vue$/,
+ loader: 'vue-loader',
+ options: {
+ loaders: {
+ scss: 'vue-style-loader!css-loader!sass-loader',
+ sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
+ }
+ }
+}
diff --git a/lib/install/config/webpack/configuration.js b/lib/install/config/webpack/configuration.js
index 607c3e52c..3617eab1c 100644
--- a/lib/install/config/webpack/configuration.js
+++ b/lib/install/config/webpack/configuration.js
@@ -6,6 +6,7 @@ const { safeLoad } = require('js-yaml')
const { readFileSync } = require('fs')
const configPath = resolve('config', 'webpack')
+const loadersDir = join(__dirname, 'loaders')
const paths = safeLoad(readFileSync(join(configPath, 'paths.yml'), 'utf8'))
const devServer = safeLoad(readFileSync(join(configPath, 'development.server.yml'), 'utf8'))
const publicPath = env.NODE_ENV !== 'production' && devServer.enabled ?
@@ -15,5 +16,6 @@ module.exports = {
devServer,
env,
paths,
+ loadersDir,
publicPath
}
diff --git a/lib/install/config/webpack/development.js b/lib/install/config/webpack/development.js
index aec3ebec6..d98ec5b13 100644
--- a/lib/install/config/webpack/development.js
+++ b/lib/install/config/webpack/development.js
@@ -1,4 +1,3 @@
-/* eslint global-require: 0 */
// Note: You must restart bin/webpack-watcher for changes to take effect
const merge = require('webpack-merge')
diff --git a/lib/install/config/webpack/paths.yml b/lib/install/config/webpack/paths.yml
index 586f77728..818d71fc8 100644
--- a/lib/install/config/webpack/paths.yml
+++ b/lib/install/config/webpack/paths.yml
@@ -4,3 +4,15 @@ entry: packs
output: public
node_modules: node_modules
source: app/javascript
+extensions:
+ - .coffee
+ - .js
+ - .jsx
+ - .ts
+ - .vue
+ - .sass
+ - .css
+ - .png
+ - .svg
+ - .gif
+ - .jpeg
diff --git a/lib/install/config/webpack/shared.js b/lib/install/config/webpack/shared.js
index 1ae61656e..39492aa44 100644
--- a/lib/install/config/webpack/shared.js
+++ b/lib/install/config/webpack/shared.js
@@ -1,15 +1,17 @@
// Note: You must restart bin/webpack-watcher for changes to take effect
+/* eslint global-require: 0 */
+/* eslint import/no-dynamic-require: 0 */
const webpack = require('webpack')
const { basename, join, resolve } = require('path')
const { sync } = require('glob')
+const { readdirSync } = require('fs')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const ManifestPlugin = require('webpack-manifest-plugin')
const extname = require('path-complete-extname')
-const { env, paths, publicPath } = require('./configuration.js')
+const { env, paths, publicPath, loadersDir } = require('./configuration.js')
-const extensions = ['.js', '.coffee']
-const extensionGlob = `*{${extensions.join(',')}}*`
+const extensionGlob = `*{${paths.extensions.join(',')}}*`
const packPaths = sync(join(paths.source, paths.entry, extensionGlob))
module.exports = {
@@ -24,45 +26,9 @@ module.exports = {
output: { filename: '[name].js', path: resolve(paths.output, paths.entry) },
module: {
- rules: [
- { test: /\.coffee(\.erb)?$/, loader: 'coffee-loader' },
- {
- test: /\.js(\.erb)?$/,
- exclude: /node_modules/,
- loader: 'babel-loader',
- options: {
- presets: [
- ['env', { modules: false }]
- ]
- }
- },
- {
- test: /\.erb$/,
- enforce: 'pre',
- exclude: /node_modules/,
- loader: 'rails-erb-loader',
- options: {
- runner: 'DISABLE_SPRING=1 bin/rails runner'
- }
- },
- {
- test: /\.(scss|sass|css)$/i,
- use: ExtractTextPlugin.extract({
- fallback: 'style-loader',
- use: ['css-loader', 'sass-loader']
- })
- },
- {
- test: /\.(jpeg|png|gif|svg|eot|svg|ttf|woff|woff2)$/i,
- use: [{
- loader: 'file-loader',
- options: {
- publicPath,
- name: env.NODE_ENV === 'production' ? '[name]-[hash].[ext]' : '[name].[ext]'
- }
- }]
- }
- ]
+ rules: readdirSync(loadersDir).map(file => (
+ require(join(loadersDir, file))
+ ))
},
plugins: [
@@ -72,7 +38,7 @@ module.exports = {
],
resolve: {
- extensions,
+ extensions: paths.extensions,
modules: [
resolve(paths.source),
resolve(paths.node_modules)
diff --git a/lib/install/examples/vue/hello_vue.js b/lib/install/examples/vue/hello_vue.js
index 5ae2e3605..6141a86ec 100644
--- a/lib/install/examples/vue/hello_vue.js
+++ b/lib/install/examples/vue/hello_vue.js
@@ -4,7 +4,7 @@
// like app/views/layouts/application.html.erb.
// All it does is render
Hello Vue
at the bottom of the page.
-import Vue from 'vue'
+import Vue from 'vue/dist/vue.esm'
import App from './app.vue'
document.addEventListener('DOMContentLoaded', () => {
diff --git a/lib/install/react.rb b/lib/install/react.rb
new file mode 100644
index 000000000..b5f3b737f
--- /dev/null
+++ b/lib/install/react.rb
@@ -0,0 +1,15 @@
+require "webpacker/configuration"
+
+puts "Copying react loader to #{Webpacker::Configuration.config_path}/loaders"
+copy_file "#{__dir__}/config/loaders/installers/react.js", "config/webpack/loaders/react.js"
+
+puts "Copying .babelrc to app root directory"
+copy_file "#{__dir__}/examples/react/.babelrc", ".babelrc"
+
+puts "Copying react example entry file to #{Webpacker::Configuration.entry_path}"
+copy_file "#{__dir__}/examples/react/hello_react.jsx", "#{Webpacker::Configuration.entry_path}/hello_react.jsx"
+
+puts "Installing all react dependencies"
+run "./bin/yarn add react react-dom babel-preset-react"
+
+puts "Webpacker now supports react.js 🎉"
diff --git a/lib/install/template.rb b/lib/install/template.rb
index 36ae1eaea..03217f3ec 100644
--- a/lib/install/template.rb
+++ b/lib/install/template.rb
@@ -1,19 +1,29 @@
-# Setup webpacker
+# Install webpacker
+puts "Creating javascript app source directory"
directory "#{__dir__}/javascript", "app/javascript"
+puts "Copying binstubs"
directory "#{__dir__}/bin", "bin"
chmod "bin", 0755 & ~File.umask, verbose: false
+puts "Copying webpack core config and loaders"
directory "#{__dir__}/config/webpack", "config/webpack"
+directory "#{__dir__}/config/loaders/core", "config/webpack/loaders"
+copy_file "#{__dir__}/config/.postcssrc.yml", ".postcssrc.yml"
append_to_file ".gitignore", <<-EOS
/public/packs
/node_modules
EOS
+puts "Installing all JavaScript dependencies"
run "./bin/yarn add webpack webpack-merge js-yaml path-complete-extname " \
"webpack-manifest-plugin babel-loader coffee-loader coffee-script " \
"babel-core babel-preset-env compression-webpack-plugin rails-erb-loader glob " \
-"extract-text-webpack-plugin node-sass file-loader sass-loader css-loader style-loader"
+"extract-text-webpack-plugin node-sass file-loader sass-loader css-loader style-loader " \
+"postcss-loader autoprefixer postcss-smart-import precss"
+puts "Installing dev server for live reloading"
run "./bin/yarn add --dev webpack-dev-server"
+
+puts "Webpacker successfully installed 🎉 🍰"
diff --git a/lib/install/vue.rb b/lib/install/vue.rb
new file mode 100644
index 000000000..512c1b998
--- /dev/null
+++ b/lib/install/vue.rb
@@ -0,0 +1,15 @@
+require "webpacker/configuration"
+
+puts "Copying vue loader to #{Webpacker::Configuration.config_path}/loaders"
+copy_file "#{__dir__}/config/loaders/installers/vue.js", "config/webpack/loaders/vue.js"
+
+puts "Copying the example entry file to #{Webpacker::Configuration.entry_path}"
+copy_file "#{__dir__}/examples/vue/hello_vue.js", "#{Webpacker::Configuration.entry_path}/hello_vue.js"
+
+puts "Copying vue app file to #{Webpacker::Configuration.entry_path}"
+copy_file "#{__dir__}/examples/vue/app.vue", "#{Webpacker::Configuration.entry_path}/app.vue"
+
+puts "Installing all vue dependencies"
+run "./bin/yarn add vue vue-loader vue-template-compiler sass-loader node-sass css-loader"
+
+puts "Webpacker now supports vue.js 🎉"
diff --git a/lib/tasks/installers/angular.rake b/lib/tasks/installers/angular.rake
index dd985705c..9bac3eb6c 100644
--- a/lib/tasks/installers/angular.rake
+++ b/lib/tasks/installers/angular.rake
@@ -1,41 +1,14 @@
-require "webpacker/configuration"
+ANGULAR_TEMPLATE_PATH = File.expand_path("../../install/angular.rb", __dir__)
namespace :webpacker do
namespace :install do
desc "Install everything needed for Angular"
task angular: ["webpacker:verify_install"] do
- shared_config_path = Webpacker::Configuration.shared_config_path
- config = File.read(shared_config_path)
-
- if config.include?("ts-loader")
- puts "The configuration file already has a reference to ts-loader, skipping the test rule..."
+ if Rails::VERSION::MAJOR >= 5
+ exec "./bin/rails app:template LOCATION=#{ANGULAR_TEMPLATE_PATH}"
else
- puts "Adding a loader rule to include ts-loader for .ts files in #{shared_config_path}..."
- config.gsub!(/rules:(\s*\[)(\s*\{)/, "rules:\\1\\2 test: /\.ts$/, loader: 'ts-loader' },\\2")
+ exec "./bin/rake rails:template LOCATION=#{ANGULAR_TEMPLATE_PATH}"
end
-
- if config =~ /["'].ts["']/
- puts "The configuration file already has a reference to .ts extension, skipping the addition of this extension to the list..."
- else
- puts "Adding '.ts' in loader extensions in #{shared_config_path}..."
- config.gsub!(/extensions = (.*')(\s*\])/, "extensions = \\1, '.ts'\\2")
- end
-
- File.write shared_config_path, config
-
- puts "Copying Angular example to #{Webpacker::Configuration.entry_path}"
- FileUtils.copy File.expand_path("../../install/examples/angular/hello_angular.js", __dir__),
- Rails.root.join(Webpacker::Configuration.entry_path, "hello_angular.js")
-
- puts "Copying Angular Hello app to #{Webpacker::Configuration.source_path}"
- FileUtils.copy_entry File.expand_path("../../install/examples/angular/hello_angular", __dir__),
- Rails.root.join(Webpacker::Configuration.source_path, "hello_angular")
-
- puts "Copying tsconfig.json to the Rails root directory"
- FileUtils.copy File.expand_path("../../install/examples/angular/tsconfig.json", __dir__),
- Rails.root.join("tsconfig.json")
-
- exec "./bin/yarn add typescript ts-loader core-js zone.js rxjs @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic"
end
end
end
diff --git a/lib/tasks/installers/react.rake b/lib/tasks/installers/react.rake
index a37d9b719..9b934403d 100644
--- a/lib/tasks/installers/react.rake
+++ b/lib/tasks/installers/react.rake
@@ -1,44 +1,14 @@
-require "webpacker/configuration"
+REACT_TEMPLATE_PATH = File.expand_path("../../install/react.rb", __dir__)
namespace :webpacker do
namespace :install do
desc "Install everything needed for react"
task react: ["webpacker:verify_install"] do
- shared_config_path = Webpacker::Configuration.shared_config_path
- config = File.read(shared_config_path)
-
- if config =~ /presets:\s*\[\s*\[\s*'env'/
- puts "Replacing loader presets to include react in #{shared_config_path}"
- config.gsub!(/presets:(\s*\[)(\s*)\[(\s)*'env'/, "presets:\\1\\2'react',\\2[\\3'env'")
- else
- puts "Couldn't automatically update loader presets in #{shared_config_path}. Please set presets: [ 'react', [ 'env', { 'modules': false } ] ]."
- end
-
- if config.include?("test: /\\.js(\\.erb)?$/")
- puts "Replacing loader test to include react in #{shared_config_path}"
- config.gsub!("test: /\\.js(\\.erb)?$/", "test: /\\.(js|jsx)?(\\.erb)?$/")
+ if Rails::VERSION::MAJOR >= 5
+ exec "./bin/rails app:template LOCATION=#{REACT_TEMPLATE_PATH}"
else
- puts "Couldn't automatically update loader test in #{shared_config_path}. Please set test: /\\.jsx?(\\.erb)?$/."
+ exec "./bin/rake rails:template LOCATION=#{REACT_TEMPLATE_PATH}"
end
-
- if config =~ /["'].jsx["']/
- puts "The configuration file already has a reference to .jsx extension, skipping the addition of this extension to the list..."
- else
- puts "Adding '.jsx' in loader extensions in #{shared_config_path}..."
- config.gsub!(/extensions = (.*')(\s*\])/, "extensions = \\1, '.jsx'\\2")
- end
-
- File.write shared_config_path, config
-
- puts "Copying .babelrc to #{Rails.root}"
- FileUtils.copy File.expand_path("../../install/examples/react/.babelrc", __dir__),
- Rails.root
-
- puts "Copying react example to #{Webpacker::Configuration.entry_path}"
- FileUtils.copy File.expand_path("../../install/examples/react/hello_react.jsx", __dir__),
- Rails.root.join(Webpacker::Configuration.entry_path, "hello_react.jsx")
-
- exec "./bin/yarn add react react-dom babel-preset-react"
end
end
end
diff --git a/lib/tasks/installers/vue.rake b/lib/tasks/installers/vue.rake
index 460fc4a8c..0f612e16d 100644
--- a/lib/tasks/installers/vue.rake
+++ b/lib/tasks/installers/vue.rake
@@ -1,35 +1,14 @@
-require "webpacker/configuration"
+VUE_TEMPLATE_PATH = File.expand_path("../../install/vue.rb", __dir__)
namespace :webpacker do
namespace :install do
desc "Install everything needed for Vue"
task vue: ["webpacker:verify_install"] do
- shared_config_path = Webpacker::Configuration.shared_config_path
- config = File.read(shared_config_path)
-
- # Module resolution https://webpack.js.org/concepts/module-resolution/
- if config.include?("'vue$':'vue/dist/vue.esm.js'")
- puts "Couldn't automatically update module resolution in #{shared_config_path}. Please set resolve { alias:{ 'vue$':'vue/dist/vue.esm.js' } }."
- else
- config.gsub!(/resolve:(\s*\{)(\s*)extensions/, "resolve:\\1\\2alias: { 'vue$':'vue/dist/vue.esm.js' },\\2extensions")
- end
-
- if config.include?("loader: 'vue-loader',")
- puts "Couldn't automatically update vue-loader in #{shared_config_path}. Please set { test: /.vue$/, loader: 'vue-loader', options: { loaders: { 'scss': 'vue-style-loader!css-loader!sass-loader', 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'}}}."
+ if Rails::VERSION::MAJOR >= 5
+ exec "./bin/rails app:template LOCATION=#{VUE_TEMPLATE_PATH}"
else
- config.gsub!(/module:(\s*\{)(\s*)rules:(\s*)\[/, "module:\\1\\2rules:\\3[\\2 {\\2 test: /\.vue$/, loader: 'vue-loader',\\2 options: {\\2 loaders: { 'scss': 'vue-style-loader!css-loader!sass-loader', 'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'}\\2 }\\2 },")
+ exec "./bin/rake rails:template LOCATION=#{VUE_TEMPLATE_PATH}"
end
-
- File.write shared_config_path, config
-
- puts "Copying the Vue example to #{Webpacker::Configuration.entry_path}"
- FileUtils.copy File.expand_path("../../install/examples/vue/hello_vue.js", File.dirname(__FILE__)),
- Rails.root.join(Webpacker::Configuration.entry_path, "hello_vue.js")
-
- FileUtils.copy File.expand_path("../../install/examples/vue/app.vue", File.dirname(__FILE__)),
- Rails.root.join(Webpacker::Configuration.entry_path, "app.vue")
-
- exec "./bin/yarn add vue vue-loader vue-template-compiler sass-loader node-sass css-loader axios"
end
end
end
diff --git a/lib/webpacker/configuration.rb b/lib/webpacker/configuration.rb
index dbd3f2232..ac96a89e6 100644
--- a/lib/webpacker/configuration.rb
+++ b/lib/webpacker/configuration.rb
@@ -3,6 +3,10 @@
class Webpacker::Configuration < Webpacker::FileLoader
class << self
+ def config_path
+ Rails.root.join(paths.fetch(:config, "config/webpack"))
+ end
+
def entry_path
Rails.root.join(source_path, paths.fetch(:entry, "packs"))
end
@@ -25,10 +29,6 @@ def paths
instance.data
end
- def shared_config_path
- Rails.root.join(paths.fetch(:config, "config/webpack"), "shared.js")
- end
-
def source_path
Rails.root.join(paths.fetch(:source, "app/javascript"))
end