# Upgrading from Shakapacker v7 to v8 The majority of the breaking changes in v8 were about dropping deprecated functions and features, along with switching to be agnostic about what package manager is used to manage JavaScript dependencies. Support for Ruby 2.6 and Node v12 has also been dropped since they're very old at this point. ## CDN host is stripped from the manifest output In Webpacker v5, the manifest.json file did not include the CDN asset host if defined. THis has been added in the aborted v6 and we've retained this in Shakapacker. Presence of this host in the output could lead to unexpected issues and required [some workarounds](https://github.com/shakacode/shakapacker/blob/main/docs/troubleshooting.md#wrong-cdn-src-from-javascript_pack_tag) in certain cases. If you are not using CDN, then this change will have no effect on your setup. If you are using CDN and your CDN host is static, `config.asset_host` setting in Rails will be respected during compilation and when referencing assets through view helpers. If your host might differ, between various environments for example, you will either need to: - Ensure the assets are specifically rebuilt for each environment (Heroku pipeline promote feature for example does not do that by default). - Make sure the assets are compiled with `SHAKAPACKER_ASSET_HOST=''` ENV variable to avoid hardcording URLs in packs output. The second option has got a certain gotcha - dynamic imports and static asset references (like image paths in CSS) will end up without a host reference and the app will try and fetch them from your app host rather than defined `config.asset_host`. To get around that, you can use dynamic override as outlined by [Webpack documentation](https://webpack.js.org/guides/asset-modules/#on-the-fly-override). Setting for example: ``` __webpack_public_path__ = 'https://mycdn.url.com/packs'; ``` In your code and ensuring it is run first in the app, will allow the dynamic imports lookup path to be overridden at runtime. You can also try Webpack `output.publicPath` option of `'auto'` as per https://webpack.js.org/guides/public-path/#automatic-publicpath. For example in your `webpack.config.js`: ``` const { generateWebpackConfig } = require('shakapacker') const customConfig = { output: { publicPath: 'auto' } }; module.exports = generateWebpackConfig(customConfig); ``` This will work in number of environments although some older browsers like IE will require a polyfill as mentioned in the Webpack documentation linked above. ## The `packageManager` property in `package.json` is used to determine the package manager The biggest functional change in v8, `shakapacker` can now work with any of the major JavaScript package managers thanks to the [`package_json`](https://github.com/shakacode/package_json) gem which uses the [`packageManager`](https://nodejs.org/api/packages.html#packagemanager) property in the `package.json`. In alignment with the behaviour of Node and `corepack`, in the absence of the `packageManager` property `npm` will be used as the package manager so as part of upgrading you will want to ensure that is set to `yarn@` if you want to continue using Yarn. An error will be raised in the presences of a lockfile other than `package-lock.json` if this property is not set with the recommended value to use, but it important the property is set to ensure all tooling uses the right package manager. The `check_yarn` rake task has also been renamed to `check_manager` to reflect this change. Check out the [installation section](../README.md#installation) of the readme for more details. ## Usages of `webpacker` must now be `shakapacker` The `webpacker` spelling was deprecated in v7 and has now been completely removed in v8 - this includes constants, environment variables, and rake tasks. If you are still using references to `webpacker`, see the [v7 Upgrade Guide](../docs/v7_upgrade.md) for how to migrate. ## JavaScript dependencies are no longer installed automatically as part of `assets:precompile` You will now need to ensure your dependencies are installed before compiling assets. Some platforms like Heroku will install dependencies automatically but if you're using a tool like `capistrano` to deploy to servers you can enhance the `assets:precompile` command like so: ```ruby namespace :assets do desc "Ensures that dependencies required to compile assets are installed" task install_dependencies: :environment do # npm v6+ raise if File.exist?("package.json") && !(system "npm ci") # yarn v1.x (classic) raise if File.exist?("package.json") && !(system "yarn install --frozen-lockfile") # yarn v2+ (berry) raise if File.exist?("package.json") && !(system "yarn install --immutable") # bun v1+ raise if File.exist?("package.json") && !(system "bun install --frozen-lockfile") # pnpm v6+ raise if File.exist?("package.json") && !(system "pnpm install --frozen-lockfile") end end Rake::Task["assets:precompile"].enhance ["assets:install_dependencies"] ``` This allows more flexibility than what `shakapacker` could provide - for example, you might only want to do an immutable install if you're in CI. ## `ensure_consistent_versioning` is now enabled by default This has `shakapacker` check that the versions of the installed Ruby gem and JavaScript package are compatible; this should only be impactful for codebases that are not using lockfiles. ## Usages of `globalMutableWebpackConfig` must be replaced with `generateWebpackConfig()` The function will return the same object with less risk: ```js // before const { globalMutableWebpackConfig, merge } = require('shakapacker'); const customConfig = { module: { rules: [ { test: require.resolve('jquery'), loader: 'expose-loader', options: { exposes: ['$', 'jQuery'] } } ] } }; module.exports = merge(globalMutableWebpackConfig, customConfig); ``` ```js // after const { generateWebpackConfig, merge } = require('shakapacker'); const customConfig = { module: { rules: [ { test: require.resolve('jquery'), loader: 'expose-loader', options: { exposes: ['$', 'jQuery'] } } ] } }; // you can also pass your config directly to the generator function to have it merged in! module.exports = merge(generateWebpackConfig(), customConfig); ``` ## `additional_paths` are now stripped just like with `source_path` This means going forward asset paths should be same regardless of their source: ```erb <%# before %> <%= image_pack_tag('marketing/images/people_looking_happy.png') %> <%# after %> <%= image_pack_tag('image/people_looking_happy.png') %> ``` ## Misc. removals In addition to the above, v8 has also removed a number of miscellaneous functions that no one is probably using anyway but technically could have been including: - `isArray` js utility function (just use `Array.isArray` directly) - `relative_url_root` config getter (it was never used) - `verify_file_existance` method (use `verify_file_existence` instead) - `https` option for `webpack-dev-server` (use `server: 'https'` instead)