diff --git a/CHANGELOG.md b/CHANGELOG.md index 62aae73ad..06bcfea24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## Unreleased + +## Added + +* Detects node package managers in following order - `yarn, npm` and finally fails with an error message instead of just depending on Yarn - [#452](https://github.com/rails/webpacker/issues/452) + +## Removed + +* Extra `ywebpacker:yarn_install` task - [#405](https://github.com/rails/webpacker/issues/405) +* Remove yarn usage inside binstubs + + ## [2.0] - 2017-05-24 diff --git a/README.md b/README.md index 58da130a5..aacc71d13 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ in which case you may not even need the asset pipeline. This is mostly relevant * Ruby 2.2+ * Rails 4.2+ * Node.js 6.4.0+ -* Yarn 0.20.1+ +* Yarn 0.20.1+ or NPM 4.2.0+ ## Features @@ -289,6 +289,7 @@ If you want to add a new loader, for example, to process `json` files via webpac ``` yarn add json-loader +npm install --save json-loader ``` And create a `json.js` file inside `loaders` directory: @@ -706,6 +707,7 @@ To add any new JS module you can use `yarn`: ```bash yarn add bootstrap material-ui +npm install --save material-ui ``` @@ -715,6 +717,7 @@ You can use yarn to add bootstrap or any other modules available on npm: ```bash yarn add bootstrap +npm install --save bootstrap ``` Import Bootstrap and theme(optional) CSS in your app/javascript/packs/app.js file: @@ -741,6 +744,7 @@ for using typescript with React: ```bash yarn add ts-loader typescript @types/react @types/react-dom +npm install --save ts-loader typescript @types/react @types/react-dom # You don't need this with typescript yarn remove prop-types @@ -794,6 +798,7 @@ you would need to follow these steps to add HTML templates support: ```bash yarn add html-loader +npm install --save html-loader ``` 2. Add html-loader to `config/webpacker/loaders/html.js` @@ -946,6 +951,7 @@ You can also use [babel-plugin-module-resolver](https://github.com/tleunen/babel ```bash yarn add babel-plugin-module-resolver +npm install --save babel-plugin-module-resolver ``` Specify the plugin in your `.babelrc` with the custom root or alias. Here's an example: diff --git a/lib/install/angular.rb b/lib/install/angular.rb index 09112d028..5924575d5 100644 --- a/lib/install/angular.rb +++ b/lib/install/angular.rb @@ -1,4 +1,7 @@ require "webpacker/configuration" +require "webpacker/node_bundler" + +node_bundler = Webpacker::NodeBundler.command puts "Copying angular loader to config/webpack/loaders" copy_file "#{__dir__}/config/loaders/installers/angular.js", "config/webpack/loaders/angular.js" @@ -13,6 +16,6 @@ copy_file "#{__dir__}/examples/angular/tsconfig.json", "tsconfig.json" puts "Installing all angular dependencies" -run "yarn add typescript ts-loader core-js zone.js rxjs @angular/core @angular/common @angular/compiler @angular/platform-browser @angular/platform-browser-dynamic" +run "#{node_bundler} 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 and typescript 🎉" diff --git a/lib/install/bin/webpack-dev-server.tt b/lib/install/bin/webpack-dev-server.tt index 58e1faad2..f314efb66 100644 --- a/lib/install/bin/webpack-dev-server.tt +++ b/lib/install/bin/webpack-dev-server.tt @@ -36,7 +36,7 @@ newenv = { "ASSET_HOST" => DEV_SERVER_HOST.shellescape }.freeze -cmdline = ["yarn", "run", "webpack-dev-server", "--", "--progress", "--color", "--config", WEBPACK_CONFIG] + ARGV +cmdline = ["node", "#{NODE_MODULES_PATH}/.bin/webpack-dev-server", "--progress", "--color", "--config", WEBPACK_CONFIG] + ARGV Dir.chdir(APP_PATH) do exec newenv, *cmdline diff --git a/lib/install/bin/webpack.tt b/lib/install/bin/webpack.tt index 31abc125e..626213f99 100644 --- a/lib/install/bin/webpack.tt +++ b/lib/install/bin/webpack.tt @@ -20,7 +20,7 @@ unless File.exist?(WEBPACK_CONFIG) end newenv = { "NODE_PATH" => NODE_MODULES_PATH.shellescape } -cmdline = ["yarn", "run", "webpack", "--", "--config", WEBPACK_CONFIG] + ARGV +cmdline = ["node", "#{NODE_MODULES_PATH}/.bin/webpack", "--config", WEBPACK_CONFIG] + ARGV Dir.chdir(APP_PATH) do exec newenv, *cmdline diff --git a/lib/install/elm.rb b/lib/install/elm.rb index 033254436..ae2bd397a 100644 --- a/lib/install/elm.rb +++ b/lib/install/elm.rb @@ -1,4 +1,8 @@ require "webpacker/configuration" +require "webpacker/node_bundler" + +node_bundler = Webpacker::NodeBundler.command +node_bundler_dev = Webpacker::NodeBundler.command_dev puts "Copying elm loader to config/webpack/loaders" copy_file "#{__dir__}/config/loaders/installers/elm.js", @@ -12,9 +16,9 @@ "#{Webpacker::Configuration.entry_path}/hello_elm.js" puts "Installing all elm dependencies" -run "yarn add elm elm-webpack-loader" -run "yarn add --dev elm-hot-loader" -run "yarn run elm package install -- --yes" +run "#{node_bundler} elm elm-webpack-loader" +run "#{node_bundler_dev} elm-hot-loader" +run "node #{Webpacker::Configuration.node_modules_bin_path}/elm-package install --yes" puts "Updating Webpack paths to include Elm file extension" insert_into_file Webpacker::Configuration.file_path, " - .elm\n", after: /extensions:\n/ diff --git a/lib/install/react.rb b/lib/install/react.rb index 9e16414de..d152a8668 100644 --- a/lib/install/react.rb +++ b/lib/install/react.rb @@ -1,6 +1,8 @@ require "webpacker/configuration" +require "webpacker/node_bundler" -babelrc = Rails.root.join(".babelrc") +node_bundler = Webpacker::NodeBundler.command +babelrc = Rails.root.join(".babelrc") if File.exist?(babelrc) react_babelrc = JSON.parse(File.read(babelrc)) @@ -26,6 +28,6 @@ copy_file "#{__dir__}/examples/react/hello_react.jsx", "#{Webpacker::Configuration.entry_path}/hello_react.jsx" puts "Installing all react dependencies" -run "yarn add react react-dom babel-preset-react prop-types" +run "#{node_bundler} react react-dom babel-preset-react prop-types" puts "Webpacker now supports react.js 🎉" diff --git a/lib/install/template.rb b/lib/install/template.rb index 9960facfc..243bd5998 100644 --- a/lib/install/template.rb +++ b/lib/install/template.rb @@ -1,3 +1,8 @@ +require "webpacker/node_bundler" + +node_bundler = Webpacker::NodeBundler.command +node_bundler_dev = Webpacker::NodeBundler.command_dev + # Install webpacker copy_file "#{__dir__}/config/webpacker.yml", "config/webpacker.yml" @@ -28,7 +33,7 @@ end puts "Installing all JavaScript dependencies" -run "yarn add webpack webpack-merge js-yaml path-complete-extname " \ +run "#{node_bundler} webpack webpack-merge js-yaml path-complete-extname " \ "webpack-manifest-plugin babel-loader@7.x coffee-loader coffee-script " \ "babel-core babel-preset-env babel-polyfill compression-webpack-plugin rails-erb-loader glob " \ "extract-text-webpack-plugin node-sass file-loader sass-loader css-loader style-loader " \ @@ -37,6 +42,6 @@ "babel-plugin-transform-object-rest-spread" puts "Installing dev server for live reloading" -run "yarn add --dev webpack-dev-server" +run "#{node_bundler_dev} webpack-dev-server" puts "Webpacker successfully installed 🎉 🍰" diff --git a/lib/install/vue.rb b/lib/install/vue.rb index 24f3c7ef7..2ab5d1359 100644 --- a/lib/install/vue.rb +++ b/lib/install/vue.rb @@ -1,4 +1,7 @@ require "webpacker/configuration" +require "webpacker/node_bundler" + +node_bundler = Webpacker::NodeBundler.command puts "Copying vue loader to config/webpack/loaders" copy_file "#{__dir__}/config/loaders/installers/vue.js", "config/webpack/loaders/vue.js" @@ -10,6 +13,6 @@ copy_file "#{__dir__}/examples/vue/app.vue", "#{Webpacker::Configuration.entry_path}/app.vue" puts "Installing all vue dependencies" -run "yarn add vue vue-loader vue-template-compiler" +run "#{node_bundler} vue vue-loader vue-template-compiler" puts "Webpacker now supports vue.js 🎉" diff --git a/lib/tasks/webpacker.rake b/lib/tasks/webpacker.rake index ab88ef176..227e19ff2 100644 --- a/lib/tasks/webpacker.rake +++ b/lib/tasks/webpacker.rake @@ -1,11 +1,9 @@ tasks = { - "webpacker:install" => "Installs and setup webpack with yarn", + "webpacker:install" => "Installs and setup webpack config and binstubs", "webpacker:compile" => "Compiles webpack bundles based on environment", "webpacker:check_node" => "Verifies if Node.js is installed", - "webpacker:check_yarn" => "Verifies if yarn is installed", "webpacker:check_binstubs" => "Verifies that bin/webpack & bin/webpack-dev-server are present", "webpacker:verify_install" => "Verifies if webpacker is installed", - "webpacker:yarn_install" => "Support for older Rails versions. Install all JavaScript dependencies as specified via Yarn", "webpacker:install:react" => "Installs and setup example React component", "webpacker:install:vue" => "Installs and setup example Vue component", "webpacker:install:angular" => "Installs and setup example Angular component", diff --git a/lib/tasks/webpacker/check_yarn.rake b/lib/tasks/webpacker/check_yarn.rake deleted file mode 100644 index 1a85083c9..000000000 --- a/lib/tasks/webpacker/check_yarn.rake +++ /dev/null @@ -1,15 +0,0 @@ -namespace :webpacker do - desc "Verifies if yarn is installed" - task :check_yarn do - required_yarn_version = "0.20.1" - - begin - yarn_version = `yarn --version` - - raise Errno::ENOENT if yarn_version.blank? || Gem::Version.new(yarn_version) < Gem::Version.new(required_yarn_version) - rescue Errno::ENOENT - $stderr.puts "Webpacker requires Yarn version >= #{required_yarn_version}. Please download and install the latest version from https://yarnpkg.com/lang/en/docs/install/" - $stderr.puts "Exiting!" && exit! - end - end -end diff --git a/lib/tasks/webpacker/compile.rake b/lib/tasks/webpacker/compile.rake index c00928e6b..b99d85d60 100644 --- a/lib/tasks/webpacker/compile.rake +++ b/lib/tasks/webpacker/compile.rake @@ -10,7 +10,7 @@ namespace :webpacker do asset_host = ActionController::Base.helpers.compute_asset_host env = { "NODE_ENV" => Webpacker.env, "ASSET_HOST" => asset_host }.freeze - stdout_str, stderr_str, status = Open3.capture3(env, "./bin/webpack") + stdout_str, stderr_str, status = Open3.capture3(env, "#{RbConfig.ruby} ./bin/webpack") if status.success? $stdout.puts "\e[32m[Webpacker] Compiled digests for all packs in #{Webpacker::Configuration.entry_path}:\e[0m" @@ -27,10 +27,6 @@ end # Compile packs after we've compiled all other assets during precompilation if Rake::Task.task_defined?("assets:precompile") Rake::Task["assets:precompile"].enhance do - unless Rake::Task.task_defined?("yarn:install") - # For Rails < 5.1 - Rake::Task["webpacker:yarn_install"].invoke - end Rake::Task["webpacker:compile"].invoke end end diff --git a/lib/tasks/webpacker/install.rake b/lib/tasks/webpacker/install.rake index 685d4fe3c..cc4a0245e 100644 --- a/lib/tasks/webpacker/install.rake +++ b/lib/tasks/webpacker/install.rake @@ -2,7 +2,7 @@ WEBPACKER_APP_TEMPLATE_PATH = File.expand_path("../../install/template.rb", __di namespace :webpacker do desc "Install webpacker in this application" - task install: [:check_node, :check_yarn] do + task install: [:check_node] do if Rails::VERSION::MAJOR >= 5 exec "#{RbConfig.ruby} ./bin/rails app:template LOCATION=#{WEBPACKER_APP_TEMPLATE_PATH}" else diff --git a/lib/tasks/webpacker/verify_install.rake b/lib/tasks/webpacker/verify_install.rake index ca20906d6..e7fdb8f37 100644 --- a/lib/tasks/webpacker/verify_install.rake +++ b/lib/tasks/webpacker/verify_install.rake @@ -2,7 +2,7 @@ require "webpacker/configuration" namespace :webpacker do desc "Verifies if webpacker is installed" - task verify_install: [:check_node, :check_yarn, :check_binstubs] do + task verify_install: [:check_node, :check_binstubs] do if File.exist?(Webpacker::Configuration.file_path) $stdout.puts "Webpacker is installed 🎉 🍰" $stdout.puts "Using #{Webpacker::Configuration.file_path} file for setting up webpack paths" diff --git a/lib/tasks/webpacker/yarn_install.rake b/lib/tasks/webpacker/yarn_install.rake deleted file mode 100644 index 40d632d07..000000000 --- a/lib/tasks/webpacker/yarn_install.rake +++ /dev/null @@ -1,6 +0,0 @@ -namespace :webpacker do - desc "Support for older Rails versions.Install all JavaScript dependencies as specified via Yarn" - task :yarn_install, [:arg1, :arg2] do |task, args| - system "yarn #{args[:arg1]} #{args[:arg2]}" - end -end diff --git a/lib/webpacker.rb b/lib/webpacker.rb index 2a2791634..c01369b7e 100644 --- a/lib/webpacker.rb +++ b/lib/webpacker.rb @@ -17,6 +17,7 @@ def env end end +require "webpacker/node_bundler" require "webpacker/env" require "webpacker/configuration" require "webpacker/manifest" diff --git a/lib/webpacker/configuration.rb b/lib/webpacker/configuration.rb index 70c5c4be9..29b43b58b 100644 --- a/lib/webpacker/configuration.rb +++ b/lib/webpacker/configuration.rb @@ -20,6 +20,10 @@ def source_path Rails.root.join(source) end + def node_modules_bin_path + Rails.root.join("node_modules", ".bin") + end + def public_path Rails.root.join("public") end diff --git a/lib/webpacker/node_bundler.rb b/lib/webpacker/node_bundler.rb new file mode 100644 index 000000000..f164a8d2d --- /dev/null +++ b/lib/webpacker/node_bundler.rb @@ -0,0 +1,67 @@ +# Finds available global or local node package manager - yarn or npm + +require "webpacker/configuration" + +module Webpacker::NodeBundler + extend self + + def name + @package ||= packages.find(-> { raise Errno::ENOENT }) { |package| available?(package) } + + rescue Errno::ENOENT + $stderr.puts "Node package managers npm and yarn not found! Scanned following paths for executables - #{packages}" + $stderr.puts "Make sure either npm or yarn is installed globally, or locally within your app node_modules folder." + exit! + end + + def command + commands[name] + end + + def command_dev + commands[:dev][name] + end + + private + + def available?(package) + null_device = Gem.win_platform? ? "/nul 2>&1" : "/dev/null 2>&1" + system("#{package} --version > #{null_device}") + end + + def commands + commands = { dev: {} } + + yarn.each do |package| + commands["#{package}"] = "#{package} add" + commands[:dev]["#{package}"] = "#{package} add --dev" + end + + npm.each do |package| + commands["#{package}"] = "#{package} install --save" + commands[:dev]["#{package}"] = "#{package} install --save-dev" + end + + commands + end + + def packages + [*yarn, *npm] + end + + def yarn + %W( + yarn + #{Webpacker::Configuration.node_modules_bin_path}/yarn + yarnpkg + #{Webpacker::Configuration.node_modules_bin_path}/yarnpkg + ).freeze + end + + def npm + %W( + npm + #{Webpacker::Configuration.node_modules_bin_path}/npm + ).freeze + end +end