Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loosen up yarn and support npm #475

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

y is extra, I think 👀

* Remove yarn usage inside binstubs


## [2.0] - 2017-05-24


Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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+
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why 4.2 and not 2, or even 1? All the npm commands here work in every version of npm. Why artificially restrict it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are they compatible with all versions of node? In webpacker node > 6.4 is required. I noticed later npm versions dropped support for node ~> 0.12

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with yarn for example a couple of issues were created relating to a particular version of yarn not working well with installed node version - so, I just wanted to make this actually works ;)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm 4.6+ doesn't work in node < v1, and npm 5+ doesn't work in node < 4. But, npm 2 works with node 6, and I believe with node 8 too.

In other words, npm might have a node requirement, but node tends to always work with older npms.

I absolutely would want someone to verify that a version of npm the docs claimed to work, works :-) and it's fine if it says 4.2 because nobody's tested older; but it'd be ideal to find the absolute lowest version of npm that works with node 6.4+ (which includes the latest version of npm 2, at the least, of that I'm certain).

Copy link

@vincemtnz vincemtnz Jun 6, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should be supporting node < 4.2, as it is most of what's under config/webpacker won't run on node < 4.2, e.g.:

const { settings, output } = require('./configuration.js')

So as far as I'm concerned webpacker already only supports node 4.2+

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds like you want node 4.2+, but that's still not a reason to restrict npm to 4.2.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit, but "npm" is always lowercase: https://twitter.com/seldo/status/850042251635867648



## Features
Expand Down Expand Up @@ -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
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

npm >=5 will save by default, so --save is not required (4th bullet on the changelog for 5.0.0)

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's only true if save=false isn't in an .npmrc file somewhere, as many of us do who don't like npm 5+'s default autosave behavior. I think it's a good idea to keep it here.

```

And create a `json.js` file inside `loaders` directory:
Expand Down Expand Up @@ -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
```


Expand All @@ -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:
Expand All @@ -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
Expand Down Expand Up @@ -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`
Expand Down Expand Up @@ -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:
Expand Down
5 changes: 4 additions & 1 deletion lib/install/angular.rb
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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 🎉"
2 changes: 1 addition & 1 deletion lib/install/bin/webpack-dev-server.tt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/install/bin/webpack.tt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 7 additions & 3 deletions lib/install/elm.rb
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -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/
Expand Down
6 changes: 4 additions & 2 deletions lib/install/react.rb
Original file line number Diff line number Diff line change
@@ -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))
Expand All @@ -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 🎉"
9 changes: 7 additions & 2 deletions lib/install/template.rb
Original file line number Diff line number Diff line change
@@ -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"

Expand Down Expand Up @@ -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 [email protected] 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 " \
Expand All @@ -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 🎉 🍰"
5 changes: 4 additions & 1 deletion lib/install/vue.rb
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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 🎉"
4 changes: 1 addition & 3 deletions lib/tasks/webpacker.rake
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
15 changes: 0 additions & 15 deletions lib/tasks/webpacker/check_yarn.rake

This file was deleted.

6 changes: 1 addition & 5 deletions lib/tasks/webpacker/compile.rake
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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
2 changes: 1 addition & 1 deletion lib/tasks/webpacker/install.rake
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/tasks/webpacker/verify_install.rake
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
6 changes: 0 additions & 6 deletions lib/tasks/webpacker/yarn_install.rake

This file was deleted.

1 change: 1 addition & 0 deletions lib/webpacker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def env
end
end

require "webpacker/node_bundler"
require "webpacker/env"
require "webpacker/configuration"
require "webpacker/manifest"
Expand Down
4 changes: 4 additions & 0 deletions lib/webpacker/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 67 additions & 0 deletions lib/webpacker/node_bundler.rb
Original file line number Diff line number Diff line change
@@ -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}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many developers will have both yarn and npm installed.

Seems like we just pick yarn if first. Should that be documented? Maybe this should just be in the config file or via an ENV, b/c those devs working on multiple projects will surely have yarn.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"surely" might be a bit strong - I work on hundreds of projects and don't have yarn installed for any of them.

I also think the presence of yarn - which perhaps one package I work on might require - shouldn't force it to use yarn. Explicit configuration when it's ambiguous might be useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@justin808 The package manager is checked in order - yarn, npm (global) and then inside node_modules (local) - don't think using either affects the code so the env or config change isn't necessary. @ljharb true, unless of course they are already using it. NPM comes bundled as default with node so, thats "surely" available on all systems that has node.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree npm will generally always be available; I'm suggesting that the mere presence of yarn doesn't indicate a preference for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A yarn.lock file will though.

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gauravtiwari Will there be too much maintenance to support (every version of) npm and yarn.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No don't think so - that was the idea actually to support everything available so, we don't say "don't have yarn, buzz off"


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