-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Changes from 15 commits
4625a6a
769cd06
5772382
443eef4
90b2462
bd5c74f
3a7fb6d
64e05e2
57b568a
573baa0
2d9d2de
dca884b
47031e4
539f448
bc12929
524c746
d73ca35
77b1cf5
64e34c0
63ae3cd
e4736d1
bb37152
596e77d
ef48e6f
2b0d4ed
ec86811
101c4f6
5842c70
d7278d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
AllCops: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use the same as rails/rails using the There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,10 +13,12 @@ cache: | |
yarn: true | ||
|
||
install: | ||
- gem install rubocop | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't this get handled by the gemfile? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
source 'https://rubygems.org' | ||
source "https://rubygems.org" | ||
|
||
gemspec |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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`. | ||
|
@@ -59,11 +61,6 @@ as Webpack calls it). | |
|
||
Let's say you're building a calendar. Your structure could look like this: | ||
|
||
```erb | ||
<%# app/views/layout/application.html.erb %> | ||
<%= javascript_pack_tag 'calendar' %> | ||
``` | ||
|
||
```js | ||
// app/javascript/packs/calendar.js | ||
require('calendar') | ||
|
@@ -72,19 +69,114 @@ require('calendar') | |
``` | ||
app/javascript/calendar/index.js // gets loaded by require('calendar') | ||
app/javascript/calendar/components/grid.jsx | ||
app/javascript/calendar/styles/grid.sass | ||
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`. | ||
```erb | ||
<%# app/views/layout/application.html.erb %> | ||
<%= javascript_pack_tag 'calendar' %> | ||
<%= stylesheet_pack_tag 'calendar' %> | ||
``` | ||
|
||
But it could also look a million other ways. | ||
|
||
## Advanced Configuration | ||
|
||
By default, webpacker offers simple conventions for where the webpack configs, javascript app files and compiled webpack bundles will go in your rails app, | ||
but all these options are configurable from `config/webpack/paths.yml` file. | ||
|
||
```yml | ||
# config/webpack/paths.yml | ||
paths: | ||
src_path: app/javascript | ||
config_path: config/webpack | ||
node_modules_path: node_modules | ||
dist_dir: packs | ||
dist_path: public/packs | ||
``` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When would these configurations differ in the different environments? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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? |
||
|
||
**Note:** If you rename `packs` directory inside `app/javascript` from `packs` to `bundles`, make sure you also update your `dist_dir` and `dist_path`. | ||
|
||
```yml | ||
paths: | ||
dist_dir: bundles | ||
dist_path: public/bundles | ||
``` | ||
|
||
Similary, you can also control and configure `webpack-dev-server` settings from | ||
`config/webpack/dev_server.yml` file | ||
|
||
```yml | ||
# config/webpack/dev_server.yml | ||
dev_server: | ||
enabled: true | ||
host: localhost | ||
port: 8080 | ||
``` | ||
|
||
By default, `webpack-dev-server` uses `dist_path` option specified in `paths.yml` as `contentBase`. | ||
|
||
**Note:** Don't forget to disable `webpack-dev-server` incase you are using | ||
`./bin/webpack-watcher` to serve assets in development mode otherwise | ||
you will get 404 for assets because the helper tag will use webpack-dev-server url | ||
to serve assets instead of public directory. | ||
|
||
## Linking to static assets | ||
|
||
Static assets like images, fonts and stylesheets support is enabled out-of-box so, you can link them into your javascript app code and have them compiled automatically. | ||
|
||
```js | ||
// React component example | ||
// app/javascripts/packs/hello_react.jsx | ||
import React from 'react' | ||
import ReactDOM from 'react-dom' | ||
import helloIcon from '../hello_react/images/icon.png' | ||
import './hello-react.sass' | ||
|
||
const Hello = props => ( | ||
<div className="hello-react"> | ||
<img src={helloIcon} alt="hello-icon" /> | ||
<p>Hello {props.name}!</p> | ||
</div> | ||
) | ||
``` | ||
|
||
under the hood webpack uses [extract-text-webpack-plugin](https://github.com/webpack-contrib/extract-text-webpack-plugin) plugin to extract all the referenced styles and compile it into a separate `[pack_name].css` bundle so that within your view you can use the `stylesheet_pack_tag` helper, | ||
|
||
```erb | ||
<%= stylesheet_pack_tag 'hello_react' %> | ||
``` | ||
|
||
## Getting asset path | ||
|
||
Webpacker provides `asset_pack_path` helper to get the path of any given asset that's been compiled by webpack. | ||
|
||
**For ex,** if you want to create a `<link rel="prefetch">` or `<img />` | ||
for an asset used in your pack code you can reference them like this in your view, | ||
|
||
```erb | ||
<%= asset_pack_path 'hello_react.css' %> | ||
<% # => "/packs/hello_react.css" %> | ||
<img src="<%= asset_pack_path 'calendar.png' %>" /> | ||
<% # => <img src="/packs/calendar.png" /> %> | ||
``` | ||
|
||
## 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"> | ||
``` | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add the |
||
## Linking to sprockets assets | ||
|
||
|
@@ -102,25 +194,42 @@ This is enabled by the `rails-erb-loader` loader rule in `config/webpack/shared. | |
|
||
## 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. | ||
|
||
## Troubleshooting | ||
|
||
* If you get this error `ENOENT: no such file or directory - node-sass` on Heroku | ||
or elsewhere during `assets:precompile` or `bundle exec rails webpacker:compile` | ||
then you would need to rebuild node-sass. It's a bit weird error, | ||
basically, it can't find the `node-sass` binary. | ||
An easy solution is to create a postinstall hook - `npm rebuild node-sass` in | ||
`package.json` and that will ensure `node-sass` is rebuild whenever | ||
you install any new modules. | ||
|
||
* If you get this error `Can't find hello_react.js in manifest.json` | ||
when loading a view in browser it's because Webpack is still compiling packs. | ||
Webpacker uses a `manifest.json` file to keep track of packs in all environments, | ||
however since this file is generated after packs are compiled by webpack. So, | ||
if you load a view in browser whilst webpack is compiling you will get this error. | ||
Therefore, make sure webpack | ||
(i.e `.bin/webpack-watcher` or `.bin/webpack-dev-sever`) is running and has | ||
completed the compilation successfully before loading a view. | ||
|
||
## 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). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,33 @@ | ||
<%= shebang %> | ||
require 'shellwords' | ||
$stdout.sync = true | ||
|
||
ENV['RAILS_ENV'] ||= 'development' | ||
RAILS_ENV = ENV['RAILS_ENV'] | ||
require "shellwords" | ||
require "yaml" | ||
|
||
ENV['NODE_ENV'] ||= RAILS_ENV | ||
NODE_ENV = ENV['NODE_ENV'] | ||
ENV["RAILS_ENV"] ||= "development" | ||
RAILS_ENV = ENV["RAILS_ENV"] | ||
|
||
APP_PATH = File.expand_path('../', __dir__) | ||
ESCAPED_APP_PATH = APP_PATH.shellescape | ||
ENV["NODE_ENV"] ||= RAILS_ENV | ||
NODE_ENV = ENV["NODE_ENV"] | ||
|
||
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" | ||
APP_PATH = File.expand_path("../", __dir__) | ||
CONFIG_PATH = File.join(APP_PATH, "config/webpack/paths.yml") | ||
|
||
# Warn the user if the configuration is not set | ||
RAILS_ENV_CONFIG = File.join("config", "environments", "#{RAILS_ENV}.rb") | ||
begin | ||
config = YAML.load(File.read(CONFIG_PATH)) | ||
|
||
# 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" | ||
NODE_MODULES_PATH = File.join(APP_PATH.shellescape, config["paths"]["node_modules_path"]) | ||
WEBPACK_CONFIG_PATH = File.join(APP_PATH.shellescape, config["paths"]["config_path"]) | ||
|
||
WEBPACK_BIN = "#{NODE_MODULES_PATH}/.bin/webpack-dev-server" | ||
DEV_SERVER_CONFIG = "#{WEBPACK_CONFIG_PATH}/development.server.js" | ||
rescue Errno::ENOENT, NoMethodError | ||
puts "Configuration not found in config/webpacker/paths.yml." | ||
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} --progress --color " \ | ||
"--config #{DEV_SERVER_CONFIG}" | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
awesome to have rubocop!