Skip to content

Commit

Permalink
Updates to upgrade guide (rails#81)
Browse files Browse the repository at this point in the history
  • Loading branch information
stevegeek authored Mar 16, 2022
1 parent e6a6fe8 commit f9e8c3b
Showing 1 changed file with 81 additions and 9 deletions.
90 changes: 81 additions & 9 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

Propshaft has a smaller scope than Sprockets, therefore migrating to it will also require you to adopt the [jsbundling-rails](https://github.com/rails/jsbundling-rails) and [cssbundling-rails](https://github.com/rails/cssbundling-rails) gems. This guide will assume your project follows Rails 6.1 conventions of using [webpacker](https://github.com/rails/webpacker) to bundle javascript, [sass-rails](https://github.com/rails/sass-rails) to bundle css and [sprockets](https://github.com/rails/sprockets) to digest assets. Finally, you will also need [npx](https://docs.npmjs.com/cli/v7/commands/npx) version 7.1.0 or later installed.

## 1. Migrate from webpacker to jsbundling-rails
Propshaft depends on Rails 7, so you will need to upgrade to Rails 7+ before starting the migration.

## 1. Migrate from Webpacker to jsbundling-rails

Start by following these steps:

Expand All @@ -11,21 +13,22 @@ Start by following these steps:
3. Run `./bin/rails javascript:install:webpack`;
4. Remove the file `config/initializers/assets.rb`;
5. Remove the file `bin/webpack`;
5. Remove the file `bin/webpack-dev-server`;
6. Remove the folder `config/webpack`;
7. Replace all instances of `javascript_pack_tag` with `javascript_include_tag` and add `defer: true` to them.
6. Remove the file `bin/webpack-dev-server`;
7. Remove the folder `config/webpack` (note: any custom configuration should be migrated to the new `webpack.config.js` file);
8. Remove the file `config/webpacker.yml`;
9. Replace all instances of `javascript_pack_tag` with `javascript_include_tag` and add `defer: true` to them.

After you are done you will notice that the install step added various files to your project and updated some of the existing ones.

**The new 'bin/dev' and 'Procfile.dev' files**

The `./bin/dev` file is a shell script that uses [foreman](https://github.com/ddollar/foreman) and `Procfile.dev` to start two processes in a single terminal: `rails s` and `yarn build`. The latter replaces `webpack-dev-server` in bundling and watching for changes in javascript files.
The `./bin/dev` file is a shell script that uses [foreman](https://github.com/ddollar/foreman) and `Procfile.dev` to start two processes in a single terminal: `rails s` and `yarn build`. The latter replaces `webpack-dev-server` for bundling and watching for changes in javascript files.

**The 'build' attribute added to packages.json**

This is the command that `yarn build` will use to bundle javascript files.

**The new 'webpack.config.js file'**
**The new 'webpack.config.js' file**

In `webpacker` this file was hidden inside the gem, but now you can edit it directly. If you had custom configuration in `config/webpack` you can move them to here. Projects with multiple entrypoints will need to adjust the `entry` attribute:

Expand Down Expand Up @@ -71,8 +74,77 @@ Then open `packages.json` and add this:

Finally, download [webpackers babel preset](https://github.com/rails/webpacker/blob/master/package/babel/preset.js) file and place it in the same directory as `packages.json` with the name `webpack.babel.js`.

**Module resolution**

Webpacker included the `source_path` (default: `app/javascript/`) into module resolution, so a statement like `import 'channels'` imported `app/javascript/channels/`. After migrating to `jsbundling-rails` this is no longer the case. You will need to update your `webpack.config.js` to include the following if you wish to maintain that behavior:

```javascript
module.exports = {
// ...
resolve: {
modules: ["app/javascript", "node_modules"],
},
//...
}
```

Alternatively, you can change modules to use relative imports, for example:
```diff
- import 'channels'
+ import './channels'
```

**Extracting Sass/SCSS from JavaScript**

In webpacker it is possible to extract Sass/SCSS from JavaScript by enabling `extract_css` in `webpacker.yml`. This allows for including those source files in JavaScript, e.g. `import '../scss/application.scss`

If you wish to keep this functionality follow these steps:

1. Run `yarn add mini-css-extract-plugin sass sass-loader css-loader`;
2. Update your `webpack.config.js` to require `mini-css-extract-plugin` and configure the loaders (see example below).

Example `webpack.config.js`:

```javascript
const path = require("path")
const webpack = require("webpack")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = {
mode: "production",
devtool: "source-map",
entry: {
application: "./app/javascript/application.js"
},
resolve: {
modules: ["app/javascript", "node_modules"],
},
output: {
filename: "[name].js",
sourceMapFilename: "[file].map",
path: path.resolve(__dirname, "app/assets/builds"),
},
plugins: [
new MiniCssExtractPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
],
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
}
```

## 2. Migrate from sass-rails to cssbundling-rails

Note: if your application used Webpacker's `extract_css` to build your CSS and did not require `sass-rails`, you can skip this section.

Start by following these steps:

1. Add `cssbundling-rails` to your Gemfile;
Expand Down Expand Up @@ -141,7 +213,7 @@ Start by following these steps:

**Asset paths**

Propshaft will automatically include in its search paths the folders `vendor/assets`, `lib/assets` and `app/assets` of your project and all the gems in your gemfile. You can see all included files by using the `reveal` rake task:
Propshaft will automatically include in its search paths the folders `vendor/assets`, `lib/assets` and `app/assets` of your project and of all the gems in your Gemfile. You can see all included files by using the `reveal` rake task:
```
rake assets:reveal
```
Expand Down Expand Up @@ -170,7 +242,7 @@ background: image_url('hero.jpg')

Using the same path with `url` in Propshaft will cause it to raise an error, saying it cannot locate `theme/hero.jpg`. That's because Propshaft assumes all paths are relative to the path of the file it's processing. Since it was processing a css file inside the `theme` folder, it will also look for `hero.jpg` in the same folder.

By adding a `/` at the start of the path we are telling Propshaft to consider to treat this path as an absolute path. While this change in behavior increases the work a bit when upgrading, it makes **external libraries like FontAwesome and Bootstrap themes work out-of-the-box**.
By adding a `/` at the start of the path we are telling Propshaft to consider this path as an absolute path. While this change in behavior increases the work a bit when upgrading, it makes **external libraries like FontAwesome and Bootstrap themes work out-of-the-box**.

**Asset content**

Expand All @@ -181,4 +253,4 @@ Rails.application.assets.load_path.find('logo.svg').content

**Precompilation in development**

Propshaft is using dynamic assets resolver in development mode. However, when you run `assets:precompile` locally - it's then switching to static assets resolver. Your changes to assets will not be anymore observed and you'd have to precompile assets each time. This is different to Sprockets.
Propshaft uses a dynamic assets resolver in development mode. However, when you run `assets:precompile` locally Propshaft will then switch to a static assets resolver. Therefore, changes to assets will not be observed anymore and you will have to precompile the assets each time changes are made. This is different to Sprockets.

0 comments on commit f9e8c3b

Please sign in to comment.