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

Add static assets support #153

Merged
merged 29 commits into from
Mar 23, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
4625a6a
Add optional static asset task, refactor configs and add new manifest…
gauravtiwari Mar 2, 2017
769cd06
Add stylesheet_pack_tag helper doc to readme
gauravtiwari Mar 7, 2017
5772382
Fix aesthetics based on code review
gauravtiwari Mar 12, 2017
443eef4
Refactor configuration and use that to fetch configs
gauravtiwari Mar 14, 2017
90b2462
Fix indentation
gauravtiwari Mar 16, 2017
bd5c74f
Use manifest.json to lookup paths in all env and get rid of redundant…
gauravtiwari Mar 16, 2017
3a7fb6d
Sync with master
gauravtiwari Mar 16, 2017
64e05e2
Remove redundant options for dev-server
gauravtiwari Mar 16, 2017
57b568a
Fix error messages
gauravtiwari Mar 16, 2017
573baa0
Fix angular and react installer to use new extenstions
gauravtiwari Mar 16, 2017
2d9d2de
Add manifest loading in block to wait if manifest doesn't exist
gauravtiwari Mar 16, 2017
dca884b
Update readme and error messages
gauravtiwari Mar 16, 2017
47031e4
Sync with master
gauravtiwari Mar 16, 2017
539f448
Use writeToFileEmit option
gauravtiwari Mar 17, 2017
bc12929
Update readme
gauravtiwari Mar 17, 2017
524c746
Fix aesthetics around configuration files
gauravtiwari Mar 20, 2017
d73ca35
Remove redundant method
gauravtiwari Mar 20, 2017
77b1cf5
Rename dev_server.yml to development.server.yml
gauravtiwari Mar 21, 2017
64e34c0
Rename webpacker:install:verify to webpacker:install_verify
gauravtiwari Mar 22, 2017
63ae3cd
Rename the task file
gauravtiwari Mar 22, 2017
e4736d1
Add a separate yarn install task to enhance precompile with yarn install
gauravtiwari Mar 22, 2017
bb37152
Move enhancement to compile task instead
gauravtiwari Mar 22, 2017
596e77d
Add a comment
gauravtiwari Mar 22, 2017
ef48e6f
Fix task description
gauravtiwari Mar 22, 2017
2b0d4ed
Add messages to verify task
gauravtiwari Mar 22, 2017
ec86811
Make sure to use paths.yml for third-party installers
gauravtiwari Mar 22, 2017
101c4f6
Use paths from configuration
gauravtiwari Mar 22, 2017
5842c70
Remove filename
gauravtiwari Mar 22, 2017
d7278d2
Refactor loaders and installers
gauravtiwari Mar 23, 2017
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
124 changes: 124 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
AllCops:
Copy link
Contributor

Choose a reason for hiding this comment

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

awesome to have rubocop!

Copy link
Member

Choose a reason for hiding this comment

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

Can we use the same as rails/rails using the inherit_from option?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should follow https://github.com/github/rubocop-github and create a gem rubocop-rails or something and use it all over the rails repositories with inherit_gem

Copy link
Member

Choose a reason for hiding this comment

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

inherit_from is sufficient. We don't need a gem if we can download the config from github.

TargetRubyVersion: 2.2
# RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
# to ignore them, so only the ones explicitly set in this file are enabled.
DisabledByDefault: true
Exclude:
- 'lib/install/templates/**'
- 'vendor/**/*'
- 'node_modules/**/*'

# Prefer &&/|| over and/or.
Style/AndOr:
Enabled: true

# Do not use braces for hash literals when they are the last argument of a
# method call.
Style/BracesAroundHashParameters:
Enabled: true

# Align `when` with `case`.
Style/CaseIndentation:
Enabled: true

# Align comments with method definitions.
Style/CommentIndentation:
Enabled: true

# No extra empty lines.
Style/EmptyLines:
Enabled: true

# In a regular class definition, no empty lines around the body.
Style/EmptyLinesAroundClassBody:
Enabled: true

# In a regular method definition, no empty lines around the body.
Style/EmptyLinesAroundMethodBody:
Enabled: true

# In a regular module definition, no empty lines around the body.
Style/EmptyLinesAroundModuleBody:
Enabled: true

# Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
Style/HashSyntax:
Enabled: true

# Method definitions after `private` or `protected` isolated calls need one
# extra level of indentation.
Style/IndentationConsistency:
Enabled: true
EnforcedStyle: rails

# Two spaces, no tabs (for indentation).
Style/IndentationWidth:
Enabled: true

Style/SpaceAfterColon:
Enabled: true

Style/SpaceAfterComma:
Enabled: true

Style/SpaceAroundEqualsInParameterDefault:
Enabled: true

Style/SpaceAroundKeyword:
Enabled: true

Style/SpaceAroundOperators:
Enabled: true

Style/SpaceBeforeFirstArg:
Enabled: true

# Defining a method with parameters needs parentheses.
Style/MethodDefParentheses:
Enabled: true

# Use `foo {}` not `foo{}`.
Style/SpaceBeforeBlockBraces:
Enabled: true

# Use `foo { bar }` not `foo {bar}`.
Style/SpaceInsideBlockBraces:
Enabled: true

# Use `{ a: 1 }` not `{a:1}`.
Style/SpaceInsideHashLiteralBraces:
Enabled: true

Style/SpaceInsideParens:
Enabled: true

# Check quotes usage according to lint rule below.
Style/StringLiterals:
Enabled: true
EnforcedStyle: double_quotes

# Detect hard tabs, no hard tabs.
Style/Tab:
Enabled: true

# Blank lines should not have any spaces.
Style/TrailingBlankLines:
Enabled: true

# No trailing whitespace.
Style/TrailingWhitespace:
Enabled: true

# Use quotes for string literals when they are enough.
Style/UnneededPercentQ:
Enabled: true

# Align `end` with the matching keyword or starting expression except for
# assignments, where it should be aligned with the LHS.
Lint/EndAlignment:
Enabled: true
EnforcedStyleAlignWith: variable

# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
Lint/RequireParentheses:
Enabled: true
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ cache:
yarn: true

install:
- gem install rubocop
Copy link
Contributor

Choose a reason for hiding this comment

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

shouldn't this get handled by the gemfile?

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 hmm, may be but don't like dependencies. Also, it seems rubocop is more kinda of standalone program now, like yarn and npm

Copy link
Member

Choose a reason for hiding this comment

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

Yes, it should be in the Gemfile. If it is a development dependency, it should be there.

- nvm install node
- node -v
- npm i -g yarn
- yarn

script:
- yarn lint
- rubocop
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
source 'https://rubygems.org'
source "https://rubygems.org"

gemspec
96 changes: 87 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ Webpacker is currently compatible with Rails 4.2+, but there's no guarantee it w
in the future.

You can either make use of Webpacker during setup of a new application with `--webpack`
or you can add the gem and run `bin/rails webpacker:install` in an existing application.
or you can add the gem and run `./bin/rails webpacker:install` in an existing application.

As the rubygems version isn't promised to be kept up to date until the release of Rails 5.1, you may want to include the gem directly from GitHub:

```ruby
gem 'webpacker', github: 'rails/webpacker'
```

You can also see a list of available commands by running `./bin/rails webpacker`

## Binstubs

Webpacker ships with three binstubs: `./bin/webpack`, `./bin/webpack-watcher` and `./bin/webpack-dev-server`.
Expand Down Expand Up @@ -78,13 +80,62 @@ app/javascript/calendar/models/month.js
But it could also look a million other ways. The only convention that Webpacker enforces is the
one where entry points are automatically configured by the files in `app/javascript/packs`.

## Advanced Configuration

By default, webpacker provides simple conventions for where the webpack configs, javascript app files and compiled webpack bundles will go in your rails app, but all these are configurable from package.json that comes with webpacker. You can also configure webpack-dev-server host and port in your development environment

```json
{
"config": {
"_comment": "Configure webpacker internals (do not remove)",
"webpacker": {
"srcPath": "app/javascript",
"configPath": "config/webpack",
"nodeModulesPath": "node_modules",
"distDir": "packs",
"distPath": "public/packs",
"digestFileName": "digests.json"
},
"_comment": "Configure webpack-dev-server",
"devServer": {
"enabled": true,
"host": "localhost",
"port": "8080",
"compress": true
}
}
}
```
Copy link
Member

Choose a reason for hiding this comment

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

When would these configurations differ in the different environments?

Copy link
Member Author

Choose a reason for hiding this comment

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

It wouldn't actually, but I added just to follow the convention in other files (database.yml) and in case someone gets fancy to change per/env basis. You suggested in another comment to split this in 2 files - perhaps just do this without env and in two files?


**For ex:** if you rename `packs` directory inside `app/javascript` from `packs` to `bundles`, make sure you also update your `distDir` and `distPath`.

```json
"webpacker": {
"distDir": "bundles",
"distPath": "public/bundles",
}
```

**Note:** Do not delete this config otherwise your app will break, unless you really know what you're doing.

## Deployment

To compile all the packs during deployment, you can use the `rails webpacker:compile` command. This
will invoke the production configuration, which includes digesting. The `javascript_pack_tag` helper
method will automatically insert the correct digest when run in production mode. Just like the asset
pipeline does it.
Webpacker hooks up a new `webpacker:compile` task to `assets:precompile`, which gets run whenever you run `assets:precompile`. The `javascript_pack_tag` and `stylesheet_pack_tag` helper method will automatically insert the correct HTML tag for compiled pack. Just like the asset pipeline does it. By default the output will look like this in different environments,

```html
<!-- In development mode with webpack-dev-server -->
<script src="http://localhost:8080/calendar.js"></script>
<link rel="stylesheet" media="screen" href="http://localhost:8080/calendar.css">
<!-- In development mode -->
<script src="/packs/calendar.js"></script>
<link rel="stylesheet" media="screen" href="/packs/calendar.css">
<!-- In production mode -->
<script src="/packs/calendar-0bd141f6d9360cf4a7f5.js"></script>
<link rel="stylesheet" media="screen" href="/packs/calendar-dc02976b5f94b507e3b6.css">
```

**Note:** *`stylesheet_pack_tag` helper is not available out-of-the-box.
Check [statics assets](#ready-for-static-assets) support section for more details.*

Copy link
Contributor

Choose a reason for hiding this comment

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

Add the stylesheet_pack_tag docs.

## Linking to sprockets assets

Expand All @@ -100,27 +151,54 @@ var railsImagePath = "<%= helpers.image_path('rails.png') %>";

This is enabled by the `rails-erb-loader` loader rule in `config/webpack/shared.js`.

## Ready for Static Assets

Static assets support isn't enabled out-of-the-box. To enable static assets support in your javascript app you will need to run `rails webpacker:install:assets` after you have installed webpacker. Once installed, you can
link static files like images and styles directly into your javascript app code and
have them properly compiled automatically.

```js
// React component example
// app/javascripts/packs/hello_react.jsx
import React from 'react'
import ReactDOM from 'react-dom'
import clockIcon from '../counter/images/clock.png'
import './hello-react.sass'

const Hello = props => (
<div className="hello-react">
<img src={clockIcon} alt="clock" />
<p>Hello {props.name}!</p>
</div>
)
```

and then within your view, include the `stylesheet_pack_tag` with the name of your pack,

```erb
<%= stylesheet_pack_tag 'hello_react' %>
```

## Ready for React

To use Webpacker with React, just create a new app with `rails new myapp --webpack=react` (or run `rails webpacker:install:react` on a Rails 5.1 app already setup with webpack), and all the relevant dependencies
To use Webpacker with React, just create a new app with `rails new myapp --webpack=react` (or run `rails webpacker:install:react` on a Rails app already setup with webpacker), and all the relevant dependencies
will be added via yarn and changes to the configuration files made. Now you can create JSX files and
have them properly compiled automatically.

## Ready for Angular with TypeScript

To use Webpacker with Angular, just create a new app with `rails new myapp --webpack=angular` (or run `rails webpacker:install:angular` on a Rails 5.1 app already setup with webpack). TypeScript support and the Angular core libraries will be added via yarn and changes to the configuration files made. An example component written in TypeScript is also added to your project in `app/javascript` so that you can experiment Angular right away.
To use Webpacker with Angular, just create a new app with `rails new myapp --webpack=angular` (or run `rails webpacker:install:angular` on a Rails app already setup with webpacker). TypeScript support and the Angular core libraries will be added via yarn and changes to the configuration files made. An example component written in TypeScript is also added to your project in `app/javascript` so that you can experiment Angular right away.

## Ready for Vue

To use Webpacker with Vue, just create a new app with `rails new myapp --webpack=vue` (or run `rails webpacker:install:vue` on a Rails 5.1 app already setup with webpack). Vue and its supported libraries will be added via yarn and changes to the configuration files made. An example component is also added to your project in `app/javascript` so that you can experiment Vue right away.
To use Webpacker with Vue, just create a new app with `rails new myapp --webpack=vue` (or run `rails webpacker:install:vue` on a Rails app already setup with webpacker). Vue and its supported libraries will be added via yarn and changes to the configuration files made. An example component is also added to your project in `app/javascript` so that you can experiment Vue right away.


## Wishlist

- Improve process for linking to assets compiled by sprockets - shouldn't need to specify
` <% helpers = ActionController::Base.helpers %>` at the beginning of each file
- Consider chunking setup
- Consider on-demand compiling with digests when digesting=true

## License
Webpacker is released under the [MIT License](https://opensource.org/licenses/MIT).
35 changes: 24 additions & 11 deletions lib/install/bin/webpack-dev-server.tt
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
<%= shebang %>
$stdout.sync = true

require 'shellwords'
require 'json'

ENV['RAILS_ENV'] ||= 'development'
RAILS_ENV = ENV['RAILS_ENV']
RAILS_ENV = ENV['RAILS_ENV']

ENV['NODE_ENV'] ||= RAILS_ENV
NODE_ENV = ENV['NODE_ENV']
NODE_ENV = ENV['NODE_ENV']

APP_PATH = File.expand_path('../', __dir__)
ESCAPED_APP_PATH = APP_PATH.shellescape

SET_NODE_PATH = "NODE_PATH=#{ESCAPED_APP_PATH}/node_modules"
WEBPACKER_BIN = "./node_modules/.bin/webpack-dev-server"
WEBPACK_CONFIG = "#{ESCAPED_APP_PATH}/config/webpack/#{NODE_ENV}.js"
begin
package_json = File.read(File.join(APP_PATH, 'package.json'))
config = JSON.parse(package_json)
Copy link
Member

Choose a reason for hiding this comment

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

No need to have package_json as it's own var. Just inline it like JSON.parse(File.read(File.join(APP_PATH, 'package.json'))).


# Warn the user if the configuration is not set
RAILS_ENV_CONFIG = File.join("config", "environments", "#{RAILS_ENV}.rb")
NODE_MODULES_PATH = "#{File.join(ESCAPED_APP_PATH, config['webpacker']['nodeModulesPath'])}"
Copy link
Member

@dhh dhh Mar 10, 2017

Choose a reason for hiding this comment

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

Don't need to what this in a string. NODE_MODULES_PATH = File.join(ESCAPED_APP_PATH, config['webpacker']['nodeModulesPath']) is good.

Copy link
Member

Choose a reason for hiding this comment

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

Also, do need ESCAPED_APP_PATH and APP_PATH. Just escape APP_PATH.

WEBPACK_CONFIG_PATH = "#{File.join(ESCAPED_APP_PATH, config['webpacker']['configPath'])}"
PACKS_PATH = "#{File.join(ESCAPED_APP_PATH, config['webpacker']['distPath'])}"
WEBPACK_BIN = "#{NODE_MODULES_PATH}/.bin/webpack-dev-server"
WEBPACK_CONFIG = "#{WEBPACK_CONFIG_PATH}/development.hot.js"
Copy link
Member

Choose a reason for hiding this comment

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

Given all the known issues with hot reloading, maybe it shouldn't be the default.

Copy link
Member Author

Choose a reason for hiding this comment

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

Perhaps, rename it to development.server.js? We never had hot reloading from start as it requires more setup and got packages for different frameworks. It's just for dev server, that supports live reloading (not hot).


# Look into the environment file for a non-commented variable declaration
unless File.foreach(File.join(APP_PATH, RAILS_ENV_CONFIG)).detect { |line| line.match(/^\s*[^#]*config\.x\.webpacker\[\:dev_server_host\].*=/) }
puts "Warning: if you want to use webpack-dev-server, you need to tell Webpacker to serve asset packs from it. Please set config.x.webpacker[:dev_server_host] in #{RAILS_ENV_CONFIG}.\n\n"
if config['devServer'] && !config['devServer']['enabled']
puts "Error: If you want to use webpack-dev-server, you will need to enable " \
"webpack-dev-server from your package.json { devServer: { enabled: true } }"
Copy link
Member

Choose a reason for hiding this comment

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

This seems weird to me. Why not just assume its enabled if the configuration for it is there?

exit!
end
rescue Errno::ENOENT, NoMethodError
puts 'Package.json or [webpacker, devServer] config key not found.'
puts 'Please run bundle exec rails webpacker:install to install webpacker'
exit!
end

Dir.chdir(APP_PATH) do
exec "#{SET_NODE_PATH} #{WEBPACKER_BIN} --config #{WEBPACK_CONFIG} --content-base #{ESCAPED_APP_PATH}/public/packs #{ARGV.join(" ")}"
exec "NODE_PATH=#{NODE_MODULES_PATH} #{WEBPACK_BIN} " \
"--config #{WEBPACK_CONFIG} --content-base #{PACKS_PATH} #{ARGV.join(" ")}"
Copy link
Contributor

Choose a reason for hiding this comment

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

--content-base #{PACKS_PATH}

Let's read that from the package.json rather than having the shell script read it.

Copy link
Member

Choose a reason for hiding this comment

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

  • 2 spaces indention.

end
23 changes: 19 additions & 4 deletions lib/install/bin/webpack.tt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<%= shebang %>
$stdout.sync = true

require 'shellwords'
require 'json'

ENV['RAILS_ENV'] ||= 'development'
RAILS_ENV = ENV['RAILS_ENV']
Expand All @@ -10,10 +13,22 @@ NODE_ENV = ENV['NODE_ENV']
APP_PATH = File.expand_path('../', __dir__)
ESCAPED_APP_PATH = APP_PATH.shellescape

SET_NODE_PATH = "NODE_PATH=#{ESCAPED_APP_PATH}/node_modules"
WEBPACK_BIN = "./node_modules/webpack/bin/webpack.js"
WEBPACK_CONFIG = "#{ESCAPED_APP_PATH}/config/webpack/#{NODE_ENV}.js"
begin
package_json = File.read(File.join(APP_PATH, 'package.json'))
config = JSON.parse(package_json)

NODE_MODULES_PATH = "#{File.join(ESCAPED_APP_PATH, config['webpacker']['nodeModulesPath'])}"
WEBPACK_CONFIG_PATH = "#{File.join(ESCAPED_APP_PATH, config['webpacker']['configPath'])}"
Copy link
Member

Choose a reason for hiding this comment

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

Same style comments as per the dev server.

rescue Errno::ENOENT, NoMethodError
puts 'Package.json or [webpacker, devServer] config key not found.'
puts 'Please run bundle exec rails webpacker:install to install webpacker'
exit!
end

WEBPACK_BIN = "#{NODE_MODULES_PATH}/.bin/webpack"
WEBPACK_CONFIG = "#{WEBPACK_CONFIG_PATH}/#{NODE_ENV}.js"

Dir.chdir(APP_PATH) do
exec "#{SET_NODE_PATH} #{WEBPACK_BIN} --config #{WEBPACK_CONFIG} #{ARGV.join(" ")}"
exec "NODE_PATH=#{NODE_MODULES_PATH} #{WEBPACK_BIN} --config #{WEBPACK_CONFIG}" \
Copy link
Contributor

Choose a reason for hiding this comment

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

see comments from prior file

" #{ARGV.join(" ")}"
end
Loading