From f641cd0aa33669634ba1ce62353a9fd61264a87e Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 12 Aug 2017 14:58:39 -0500 Subject: [PATCH 01/11] Add HMR --- lib/install/config/webpack/development.js | 11 +++++++++-- lib/install/config/webpacker.yml | 1 + lib/webpacker/dev_server.rb | 4 ++++ lib/webpacker/helper.rb | 7 ++++++- 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/lib/install/config/webpack/development.js b/lib/install/config/webpack/development.js index 6dfb717e8..c67d4c869 100644 --- a/lib/install/config/webpack/development.js +++ b/lib/install/config/webpack/development.js @@ -1,5 +1,6 @@ // Note: You must restart bin/webpack-dev-server for changes to take effect +const webpack = require('webpack') const merge = require('webpack-merge') const sharedConfig = require('./shared.js') const { settings, output } = require('./configuration.js') @@ -14,7 +15,8 @@ module.exports = merge(sharedConfig, { devServer: { clientLogLevel: 'none', host: settings.dev_server.host, - port: settings.dev_server.port, + port: settings.dev_server.port + hmr: settings.dev_server.hmr, contentBase: output.path, publicPath: output.publicPath, compress: true, @@ -26,5 +28,10 @@ module.exports = merge(sharedConfig, { stats: { errorDetails: true } - } + }, + + plugins: settings.dev_server.hmr ? [ + new webpack.HotModuleReplacementPlugin(), + new webpack.NamedModulesPlugin() + ] : [] }) diff --git a/lib/install/config/webpacker.yml b/lib/install/config/webpacker.yml index 521ef0bd4..95391250b 100644 --- a/lib/install/config/webpacker.yml +++ b/lib/install/config/webpacker.yml @@ -14,6 +14,7 @@ default: &default dev_server: &dev_server host: localhost port: 3035 + hmr: false extensions: - .coffee diff --git a/lib/webpacker/dev_server.rb b/lib/webpacker/dev_server.rb index bac89071f..ad6f5a2a7 100644 --- a/lib/webpacker/dev_server.rb +++ b/lib/webpacker/dev_server.rb @@ -12,6 +12,10 @@ def running? false end + def hot_module_replacing? + fetch(:hmr) + end + def host fetch(:host) end diff --git a/lib/webpacker/helper.rb b/lib/webpacker/helper.rb index 191ad4adc..9bdb216f3 100644 --- a/lib/webpacker/helper.rb +++ b/lib/webpacker/helper.rb @@ -32,6 +32,9 @@ def javascript_pack_tag(*names, **options) # in config/webpack/shared.js. By default, this list is auto-generated to match everything in # app/javascript/packs/*.js. In production mode, the digested reference is automatically looked up. # + # Note: If the development server is running and hot module replacement is active, this will return nothing. + # In that setup you need to configure your styles to be inlined in your JavaScript for hot reloading. + # # Examples: # # # In development mode: @@ -42,7 +45,9 @@ def javascript_pack_tag(*names, **options) # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # => # def stylesheet_pack_tag(*names, **options) - stylesheet_link_tag(*sources_from_pack_manifest(names, type: :stylesheet), **options) + unless Webpacker.dev_server.running? && Webpacker.dev_server.hot_module_replacing? + stylesheet_link_tag(*sources_from_pack_manifest(names, type: :stylesheet), **options) + end end private From 97a8d00089c3bf39e66b2aa85ffab39781626b34 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Sat, 12 Aug 2017 15:08:56 -0500 Subject: [PATCH 02/11] Fix development.js changes --- lib/install/config/webpack/development.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/install/config/webpack/development.js b/lib/install/config/webpack/development.js index c67d4c869..92382357c 100644 --- a/lib/install/config/webpack/development.js +++ b/lib/install/config/webpack/development.js @@ -15,8 +15,8 @@ module.exports = merge(sharedConfig, { devServer: { clientLogLevel: 'none', host: settings.dev_server.host, - port: settings.dev_server.port - hmr: settings.dev_server.hmr, + port: settings.dev_server.port, + hot: settings.dev_server.hmr, contentBase: output.path, publicPath: output.publicPath, compress: true, From a6bc2ce9f59c73ca6ca9b007f54c9aadad837556 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 22:33:36 +0100 Subject: [PATCH 03/11] Update sass loader and remove redundant config from vue loader --- lib/install/config/loaders/core/sass.js | 33 +++++++++++++------ .../config/loaders/installers/react.js | 8 ++++- lib/install/config/loaders/installers/vue.js | 33 +------------------ 3 files changed, 31 insertions(+), 43 deletions(-) diff --git a/lib/install/config/loaders/core/sass.js b/lib/install/config/loaders/core/sass.js index 1fb428c4a..43e3a374c 100644 --- a/lib/install/config/loaders/core/sass.js +++ b/lib/install/config/loaders/core/sass.js @@ -3,16 +3,29 @@ const path = require('path') const { env } = require('../configuration.js') const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml') +const isProduction = env.NODE_ENV === 'production' -module.exports = { +const styleLoader = 'style-loader' +const cssLoader = { loader: 'css-loader', options: { minimize: isProduction } } +const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } } +const resolveLoader = 'resolve-url-loader' +const sassLoader = { loader: 'sass-loader', options: { sourceMap: true, indentedSyntax: true } } + +const extractOptions = { + fallback: styleLoader, + use: [cssLoader, postcssLoader, resolveLoader, sassLoader] +} + +// For production extract styles to a separate bundle +const extractLoader = { test: /\.(scss|sass|css)$/i, - use: ExtractTextPlugin.extract({ - fallback: 'style-loader', - use: [ - { loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } }, - { loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } }, - 'resolve-url-loader', - { loader: 'sass-loader', options: { sourceMap: true } } - ] - }) + use: ExtractTextPlugin.extract(extractOptions) } + +// For hot-reloading use regular loaders +const inlineLoader = { + test: /\.(scss|sass|css)$/i, + use: [styleLoader].concat(extractOptions.use) +} + +module.exports = isProduction ? extractLoader : inlineLoader diff --git a/lib/install/config/loaders/installers/react.js b/lib/install/config/loaders/installers/react.js index cfd641774..6c3341c73 100644 --- a/lib/install/config/loaders/installers/react.js +++ b/lib/install/config/loaders/installers/react.js @@ -1,5 +1,11 @@ +const { join } = require('path') +const { settings } = require('../configuration.js') + module.exports = { test: /\.(js|jsx)?(\.erb)?$/, exclude: /node_modules/, - loader: 'babel-loader' + loader: 'babel-loader', + options: { + cacheDirectory: join(settings.cache_path, 'babel-loader') + } } diff --git a/lib/install/config/loaders/installers/vue.js b/lib/install/config/loaders/installers/vue.js index c9d88a9a3..e08f88c14 100644 --- a/lib/install/config/loaders/installers/vue.js +++ b/lib/install/config/loaders/installers/vue.js @@ -1,41 +1,10 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin') const { env } = require('../configuration.js') -// Change it to false if you prefer Vue styles to be inlined by javascript in runtime -const extractStyles = false - -const cssLoader = [ - { loader: 'css-loader', options: { minimize: env.NODE_ENV === 'production' } }, - { loader: 'postcss-loader', options: { sourceMap: true } }, - 'resolve-url-loader' -] -const sassLoader = cssLoader.concat([ - { loader: 'sass-loader', options: { sourceMap: true, indentedSyntax: true } } -]) -const scssLoader = cssLoader.concat([ - { loader: 'sass-loader', options: { sourceMap: true } } -]) - -function vueStyleLoader(loader) { - if (extractStyles) { - return ExtractTextPlugin.extract({ - fallback: 'vue-style-loader', - use: loader - }) - } - return ['vue-style-loader'].concat(loader) -} - module.exports = { test: /\.vue$/, loader: 'vue-loader', options: { - loaders: { - js: 'babel-loader', - file: 'file-loader', - css: vueStyleLoader(cssLoader), - scss: vueStyleLoader(scssLoader), - sass: vueStyleLoader(sassLoader) - } + extractCSS: env.NODE_ENV === 'production' } } From f4654deea952d507a4f6efa1ad3d4dc0c4592a3b Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 22:37:48 +0100 Subject: [PATCH 04/11] Remove redundant variables --- lib/install/config/loaders/core/sass.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/install/config/loaders/core/sass.js b/lib/install/config/loaders/core/sass.js index 43e3a374c..6c90becd3 100644 --- a/lib/install/config/loaders/core/sass.js +++ b/lib/install/config/loaders/core/sass.js @@ -5,27 +5,26 @@ const { env } = require('../configuration.js') const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml') const isProduction = env.NODE_ENV === 'production' -const styleLoader = 'style-loader' -const cssLoader = { loader: 'css-loader', options: { minimize: isProduction } } -const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } } -const resolveLoader = 'resolve-url-loader' -const sassLoader = { loader: 'sass-loader', options: { sourceMap: true, indentedSyntax: true } } - const extractOptions = { - fallback: styleLoader, - use: [cssLoader, postcssLoader, resolveLoader, sassLoader] + fallback: 'style-loader', + use: [ + { loader: 'css-loader', options: { minimize: isProduction } }, + { loader: 'postcss-loader', options: { sourceMap: true, config: { path: postcssConfigPath } } }, + 'resolve-url-loader', + { loader: 'sass-loader', options: { sourceMap: true, indentedSyntax: true } } + ] } // For production extract styles to a separate bundle -const extractLoader = { +const extractCSSLoader = { test: /\.(scss|sass|css)$/i, use: ExtractTextPlugin.extract(extractOptions) } // For hot-reloading use regular loaders -const inlineLoader = { +const inlineCSSLoader = { test: /\.(scss|sass|css)$/i, - use: [styleLoader].concat(extractOptions.use) + use: ['style-loader'].concat(extractOptions.use) } -module.exports = isProduction ? extractLoader : inlineLoader +module.exports = isProduction ? extractCSSLoader : inlineCSSLoader From 686e41b8d150169d75311d29d6d8136196b65cff Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 22:53:09 +0100 Subject: [PATCH 05/11] Update condition for extracting CSS --- lib/install/config/loaders/core/sass.js | 5 +++-- lib/install/config/loaders/installers/vue.js | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/install/config/loaders/core/sass.js b/lib/install/config/loaders/core/sass.js index 6c90becd3..380d3f779 100644 --- a/lib/install/config/loaders/core/sass.js +++ b/lib/install/config/loaders/core/sass.js @@ -1,9 +1,10 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin') const path = require('path') -const { env } = require('../configuration.js') +const { env, settings } = require('../configuration.js') const postcssConfigPath = path.resolve(process.cwd(), '.postcssrc.yml') const isProduction = env.NODE_ENV === 'production' +const extractCSS = !settings.dev_server.hmr const extractOptions = { fallback: 'style-loader', @@ -27,4 +28,4 @@ const inlineCSSLoader = { use: ['style-loader'].concat(extractOptions.use) } -module.exports = isProduction ? extractCSSLoader : inlineCSSLoader +module.exports = isProduction || extractCSS ? extractCSSLoader : inlineCSSLoader diff --git a/lib/install/config/loaders/installers/vue.js b/lib/install/config/loaders/installers/vue.js index e08f88c14..2eb800c65 100644 --- a/lib/install/config/loaders/installers/vue.js +++ b/lib/install/config/loaders/installers/vue.js @@ -1,10 +1,13 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin') -const { env } = require('../configuration.js') +const { env, settings } = require('../configuration.js') + +const isProduction = env.NODE_ENV === 'production' +const extractCSS = !settings.dev_server.hmr module.exports = { test: /\.vue$/, loader: 'vue-loader', options: { - extractCSS: env.NODE_ENV === 'production' + extractCSS: isProduction || extractCSS } } From 7cbf899972f5640ecd44e8f03161608b65f18575 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 23:01:55 +0100 Subject: [PATCH 06/11] Update readme and changelog --- CHANGELOG.md | 2 ++ README.md | 29 ++++++++++++----------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c72f7c5c..3488b0a7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,8 @@ - Move dev-server config options under defaults so it's transparently available in all environments +- Add new `HMR` option for hot-module-replacement + ### Removed diff --git a/README.md b/README.md index d9e23e69b..f6d166f66 100644 --- a/README.md +++ b/README.md @@ -251,8 +251,8 @@ in a separate terminal from `./bin/rails server`. This process will watch for ch in the `app/javascript/packs/*.js` files and automatically reload the browser to match. Once you start this development server, Webpacker will automatically start proxying all -webpack asset requests to this server. When you stop the server, it'll revert to -on-demand compilation again. +webpack asset requests to this server. When you stop the server, it'll revert to +on-demand compilation again. You can also pass CLI options supported by [webpack-dev-server](https://webpack.js.org/configuration/dev-server/). Please note that inline options will always take precedence over the ones already set in the configuration file. @@ -330,11 +330,12 @@ Similary you can also control and configure `webpack-dev-server` settings from ` # config/webpacker.yml development: dev_server: - host: 0.0.0.0 + host: localhost port: 8080 - https: false ``` +If you have `hmr` turned to true, then the `stylesheet_pack_tag` generates no output, as you will want to configure your styles to be inlined in your JavaScript for hot reloading. During production and testing, the `stylesheet_pack_tag` will create the appropriate HTML tags. + #### Resolved Paths If you are adding webpacker to an existing app that has most of the assets inside @@ -398,24 +399,18 @@ plugins: Webpacker out-of-the-box provides CDN support using your Rails app `config.action_controller.asset_host` setting. If you already have [CDN](http://guides.rubyonrails.org/asset_pipeline.html#cdns) added in your rails app you don't need to do anything extra for webpacker, it just works. -### HTTPS in development - -If you're using the `webpack-dev-server` in development, you can serve views over HTTPS -by setting the `https` option for `webpack-dev-server` to `true` in `config/webpacker.yml`, -then start the dev server as usual with `./bin/webpack-dev-server`. - -Please note that the `webpack-dev-server` will use a self-signed certificate, -so your web browser will display a warning upon accessing the page. - - ### Hot module replacement -Webpacker out-of-the-box doesn't ship with HMR just yet. You will need to -install additional plugins for Webpack if you want to add HMR support. +Webpacker out-of-the-box supports HMR with `webpack-dev-server` and +you can enable it by setting `dev_server/hmr` option to `true` inside webpacker.yml. -You can checkout these links on this subject: +Checkout these guide for more information: - https://webpack.js.org/configuration/dev-server/#devserver-hot + +To add HMR for React you would need to add `react-hot-loader`. Checkout this guide for +more detailed information: + - https://webpack.js.org/guides/hmr-react/ From 7989628eaec039397fa9f2e8875efecdc8c4a0a4 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 23:03:38 +0100 Subject: [PATCH 07/11] Fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f6d166f66..40ef8272c 100644 --- a/README.md +++ b/README.md @@ -402,13 +402,13 @@ you don't need to do anything extra for webpacker, it just works. ### Hot module replacement Webpacker out-of-the-box supports HMR with `webpack-dev-server` and -you can enable it by setting `dev_server/hmr` option to `true` inside webpacker.yml. +you can toggle it by setting `dev_server/hmr` inside webpacker.yml. Checkout these guide for more information: - https://webpack.js.org/configuration/dev-server/#devserver-hot -To add HMR for React you would need to add `react-hot-loader`. Checkout this guide for +To support HMR with React you would need to add `react-hot-loader`. Checkout this guide for more detailed information: - https://webpack.js.org/guides/hmr-react/ From c8260d616c64504b36992eb06d2c7ea9b4cb9707 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Sat, 12 Aug 2017 23:12:57 +0100 Subject: [PATCH 08/11] Make linter happy --- lib/install/config/loaders/installers/vue.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/install/config/loaders/installers/vue.js b/lib/install/config/loaders/installers/vue.js index 2eb800c65..40986af2c 100644 --- a/lib/install/config/loaders/installers/vue.js +++ b/lib/install/config/loaders/installers/vue.js @@ -1,7 +1,6 @@ -const ExtractTextPlugin = require('extract-text-webpack-plugin') const { env, settings } = require('../configuration.js') -const isProduction = env.NODE_ENV === 'production' +const isProduction = env.NODE_ENV === 'production' const extractCSS = !settings.dev_server.hmr module.exports = { From 63cddc5e991db5c012e226ab52e4d37e1bdcce2a Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Mon, 14 Aug 2017 09:41:37 +0100 Subject: [PATCH 09/11] Add a comment for HMR mode Lowercase --- lib/webpacker/helper.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/webpacker/helper.rb b/lib/webpacker/helper.rb index 9bdb216f3..4e9feae23 100644 --- a/lib/webpacker/helper.rb +++ b/lib/webpacker/helper.rb @@ -41,6 +41,10 @@ def javascript_pack_tag(*names, **options) # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # => # # + # # In development mode with hot module replacement: + # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # => + # nil + # # # In production mode: # <%= stylesheet_pack_tag 'calendar', 'data-turbolinks-track': 'reload' %> # => # From 51b34ce8647f59c9646f9bbba60bb3565d7b7a40 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Tue, 15 Aug 2017 18:20:35 +0100 Subject: [PATCH 10/11] Add a note to turn off HMR --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 2d56dfe7f..90b20801f 100644 --- a/README.md +++ b/README.md @@ -413,6 +413,9 @@ more detailed information: - https://webpack.js.org/guides/hmr-react/ +**Note:** Don't forget to disable `HMR` if you are not running `webpack-dev-server` +otherwise you will get not found error for stylesheets. + ## Linking Styles, Images and Fonts From 8c1dd9664fc435fb9c2ca7f473a3acc8df806623 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Tue, 15 Aug 2017 18:22:12 +0100 Subject: [PATCH 11/11] Fix wording --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 90b20801f..da200c7c1 100644 --- a/README.md +++ b/README.md @@ -402,14 +402,14 @@ you don't need to do anything extra for webpacker, it just works. ### Hot module replacement Webpacker out-of-the-box supports HMR with `webpack-dev-server` and -you can toggle it by setting `dev_server/hmr` inside webpacker.yml. +you can toggle it by setting `dev_server/hmr` option inside webpacker.yml. -Checkout these guide for more information: +Checkout this guide for more information: - https://webpack.js.org/configuration/dev-server/#devserver-hot To support HMR with React you would need to add `react-hot-loader`. Checkout this guide for -more detailed information: +more information: - https://webpack.js.org/guides/hmr-react/