Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Changes since last non-beta release.

_Please add entries here for your pull requests that are not yet released._

### Added
- Support passing custom webpack config directly to `generateWebpackConfig` for merging [PR 343](https://github.com/shakacode/shakapacker/pull/343) by [G-Rath](https://github.com/g-rath)

### Fixed
- Use `NODE_OPTIONS` to enable Node-specific debugging flags [PR 350](https://github.com/shakacode/shakapacker/pull/350)

Expand Down
49 changes: 29 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -465,26 +465,40 @@ First, you don't _need_ to use Shakapacker's webpack configuration. However, the

1. Your output files go to the right directory
2. Your output includes a manifest, via package [`webpack-assets-manifest`](https://github.com/webdeveric/webpack-assets-manifest) that maps output names (your 'packs') to the fingerprinted versions, including bundle-splitting dependencies. That's the main secret sauce of Shakapacker!

The webpack configuration used by Shakapacker lives in `config/webpack/webpack.config.js`; this makes it easy to customize the configuration beyond what's available in `config/shakapacker.yml` by giving you complete control of the final configuration. By default, this file exports the result of `generateWebpackConfig` which handles generating a webpack configuration based on `config/shakapacker.yml`.

The most practical webpack configuration is to take the default from Shakapacker and then use [webpack-merge](https://github.com/survivejs/webpack-merge) to merge your customizations with the default. For example, suppose you want to add some `resolve.extensions`:
The easiest way to modify this config is to pass your desired customizations to `generateWebpackConfig` which will use [webpack-merge](https://github.com/survivejs/webpack-merge) to merge them with the configuration generated from `config/shakapacker.yml`:

```js
// use the new NPM package name, `shakapacker`.
// merge is webpack-merge from https://github.com/survivejs/webpack-merge
// config/webpack/webpack.config.js
const { generateWebpackConfig } = require('shakapacker')

const options = {
resolve: {
extensions: ['.css', '.ts', '.tsx']
}
}

// This results in a new object copied from the mutable global
module.exports = generateWebpackConfig(options)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

  1. It's not clear where to place this code. What file is this?
  2. With the new object rather than global, some people might get confused if they are migrating old code of multiple files that simply mutated the global object.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

These changes might be fine as-is...just some thoughts.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@justin808 I've reworded the documentation to make it clearer where the file lives. I'm not sure what you mean by your second point though?

```

The `shakapacker` package also exports the `merge` function from [webpack-merge](https://github.com/survivejs/webpack-merge) to make it easier to do more advanced customizations:

```js
// config/webpack/webpack.config.js
const { generateWebpackConfig, merge } = require('shakapacker')

const baseWebpackConfig = generateWebpackConfig()
const webpackConfig = generateWebpackConfig()

const options = {
resolve: {
extensions: ['.css', '.ts', '.tsx']
extensions: ['.css', '.ts', '.tsx']
}
}

// Copy the object using merge b/c the baseClientWebpackConfig is a mutable global
// If you want to use this object for client and server rendering configurations,
// having a new object is essential.
module.exports = merge({}, baseWebpackConfig, options)
module.exports = merge(options, webpackConfig)
```

This example is based on [an example project](https://github.com/shakacode/react_on_rails_tutorial_with_ssr_and_hmr_fast_refresh/blob/master/config/webpack/webpack.config.js)
Expand Down Expand Up @@ -513,12 +527,11 @@ Then `require` this file in your `config/webpack/webpack.config.js`:
```js
// config/webpack/webpack.config.js
// use the new NPM package name, `shakapacker`.
const { generateWebpackConfig, merge } = require('shakapacker')
const { generateWebpackConfig } = require('shakapacker')

const webpackConfig = generateWebpackConfig()
const customConfig = require('./custom')

module.exports = merge(webpackConfig, customConfig)
module.exports = generateWebpackConfig(customConfig)
```

If you need access to configs within Shakapacker's configuration, you can import them like so:
Expand Down Expand Up @@ -616,12 +629,10 @@ Then modify the webpack config to use it as a plugin:

```js
// config/webpack/webpack.config.js
const { generateWebpackConfig, merge } = require("shakapacker");

const webpackConfig = generateWebpackConfig()
const { generateWebpackConfig } = require("shakapacker");
const ForkTSCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");

module.exports = merge(webpackConfig, {
module.exports = generateWebpackConfig({
plugins: [new ForkTSCheckerWebpackPlugin()],
});
```
Expand All @@ -638,17 +649,15 @@ Optionally, add the `CSS` extension to webpack config for easy resolution.

```js
// config/webpack/webpack.config.js
const { generateWebpackConfig, merge } = require('shakapacker')

const webpackConfig = generateWebpackConfig()
const { generateWebpackConfig } = require('shakapacker')

const customConfig = {
resolve: {
extensions: ['.css']
}
}

module.exports = merge(webpackConfig, customConfig)
module.exports = generateWebpackConfig(customConfig)
```

To enable `PostCSS`, `Sass` or `Less` support, add `CSS` support first and
Expand Down
12 changes: 4 additions & 8 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,9 @@ To silent these warnings, please update `config/webpack/webpack.config.js`:
```js
const webpack = require('webpack')
const { resolve } = require('path')
const { generateWebpackConfig, merge } = require('shakapacker')
const { generateWebpackConfig } = require('shakapacker')

const webpackConfig = generateWebpackConfig();

module.exports = merge(webpackConfig, {
module.exports = generateWebpackConfig({
plugins: [
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)(@angular|esm5)/,
Expand Down Expand Up @@ -201,11 +199,9 @@ Instead do:
// config/webpack/webpack.config.js

const webpack = require('webpack')
const { generateWebpackConfig, merge } = require('shakapacker')

const webpackConfig = generateWebpackConfig();
const { generateWebpackConfig } = require('shakapacker')

module.exports = merge(webpackConfig, {
module.exports = generateWebpackConfig({
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
Expand Down
6 changes: 2 additions & 4 deletions docs/using_esbuild_loader.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,9 @@ o do so, you need to modify your webpack configuration and use `ESBuildMinifyPlu
Example:

```js
const { generateWebpackConfig, merge } = require('shakapacker')
const { generateWebpackConfig } = require('shakapacker')
const { ESBuildMinifyPlugin } = require('esbuild-loader')

const baseWebpackConfig = generateWebpackConfig()

const options = {
optimization: {
minimizer: [
Expand All @@ -74,7 +72,7 @@ const options = {
}
}

module.exports = merge({}, baseWebpackConfig, options)
module.exports = generateWebpackConfig(options)
```

For more details, see instructions at https://github.com/shakacode/shakapacker#webpack-configuration and https://github.com/privatenumber/esbuild-loader#js-minification-eg-terser.
Expand Down
24 changes: 24 additions & 0 deletions package/__tests__/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const index = require('../index')
const { generateWebpackConfig } = require("../index");

describe('index', () => {
test('exports webpack-merge v5 functions', () => {
Expand All @@ -19,4 +20,27 @@ describe('index', () => {
expect(webpackConfig2).not.toHaveProperty('newKey')
expect(webpackConfig2.output.path).not.toEqual('new value')
})

test('webpackConfig merges extra config', () => {
const { generateWebpackConfig } = require('../index')

const webpackConfig = generateWebpackConfig({
newKey: 'new value',
output: {
path: 'new path'
}
})

expect(webpackConfig).toHaveProperty('newKey', 'new value')
expect(webpackConfig).toHaveProperty('output.path', 'new path')
expect(webpackConfig).toHaveProperty('output.publicPath', '/packs/')
})

test('webpackConfig errors if multiple configs are provided', () => {
const { generateWebpackConfig } = require('../index')

expect(() => generateWebpackConfig({}, {})).toThrow(
'use webpack-merge to merge configs before passing them to Shakapacker'
)
})
})
2 changes: 1 addition & 1 deletion package/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ declare module 'shakapacker' {

export const config: Config
export const devServer: Record<string, unknown>
export function generateWebpackConfig(): Configuration
export function generateWebpackConfig(extraConfig?: Configuration): Configuration
export const globalMutableWebpackConfig: Configuration
export const baseConfig: Configuration
export const env: Env
Expand Down
10 changes: 8 additions & 2 deletions package/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,15 @@ const globalMutableWebpackConfig = () => {
return environmentConfig
}

const generateWebpackConfig = () => {
const generateWebpackConfig = (extraConfig = {}, ...extraArgs) => {
if (extraArgs.length > 0) {
throw new Error(
'Only one extra config may be passed here - use webpack-merge to merge configs before passing them to Shakapacker'
)
}

const environmentConfig = globalMutableWebpackConfig()
const immutable = webpackMerge.merge({}, environmentConfig)
const immutable = webpackMerge.merge({}, environmentConfig, extraConfig)
return immutable
}

Expand Down
2 changes: 1 addition & 1 deletion spec/dummy/config/webpack/commonWebpackConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ const ignoreWarningsConfig = {
};
// Copy the object using merge b/c the baseClientWebpackConfig and commonOptions are mutable globals
// const commonWebpackConfig = () => (merge({}, baseClientWebpackConfig, commonOptions))
const commonWebpackConfig = () => (merge({}, generateWebpackConfig(), commonOptions, ignoreWarningsConfig))
const commonWebpackConfig = () => generateWebpackConfig(merge(commonOptions, ignoreWarningsConfig))

module.exports = commonWebpackConfig