RedwoodJS

# Webpack Configuration

Redwood uses webpack. And with webpack, comes configuration.

One of Redwood's tenets is convention over configuration. So it's worth repeating that you don't have to do any of this. Take the golden path, and everything will work just fine.

But another of Redwood's tenets is to make the hard stuff possible. Whether Webpack configuration falls into the hard-stuff category or not is up for debate. But one thing we know for sure is it can be an epic time sink. We hope that documenting it well will make this process fast, easy, and maybe even enjoyable.

While configuring webpack, at some point, you may wonder what exactly our configuration is. The following section aims to explain that. But if you just want to configure webpack, jump to Configuring Webpack.

# Redwood's Webpack Configuration Files

You can find Redwood's webpack config files in @redwoodjs/core's config directory. There's four altogether:

File Description
webpack.common.js Base config; merges with development, production, and user-defined configs
webpack.development.js Config used when developing locally
webpack.production.js Config used when building for production
webpack.stat.js Config used when --stats is provided to yarn rw build; merges the production config with Webpack Bundle Analyzer

# webpack.common.js

This is the base config; it merges with the development and production configs, configures options common to both, and merges the user-defined config along the way.

This is where the bulk of the configuration happens. Since we distinguish between a development and production configs, we do as the docs say and export a function.

Here's a table of some of the plugins we use:

Plugin Description
HtmlWebpackPlugin Simplifies the creation of HTML files to serve your webpack bundles
DirectoryNamedWebpackPlugin Makes it possible to control which file in a directory will be treated as the entry file
MiniCssExtractPlugin Extracts CSS into separate files
CopyWebpackPlugin Copies individual files or entire directories, which already exist, to the build directory
DotenvPlugin Exposes (a subset of) dotenv variables

# webpack.development.js

This is the config used when developing locally. yarn rw dev starts webpack-dev-server with this config.

With webpack dev server, files aren't written to disk, so you won't see anything in dist. Nor do we do any optimizations.

The main thing to configure here is devServer. But you can already configure many of its options via redwood.toml—see App Configuration: redwood.toml.

# webpack.production.js

This is the config used when building for production (yarn rw build). There's not much here right now.

# webpack.stat.js

Redwood bundles with webpack.stat.js if you provide the --stats option to yarn rw build:

yarn rw build --stats

Note that this'll skip building the api side.

This config uses Webpack Bundle Analyzer. When it finishes, it'll launch an interactive zoomable, treemap in your browser to examine the contents of all your bundles.

# Supported Extensions and Loaders

When a file is imported, Redwood runs one of the following loaders in the following order:

Order File Loader
1. .md, .test.js, .stories.js null-loader
2. .js, .jsx, .ts., .tsx babel
3. .css, .scss, .module.css, .module.scss sass-loader, css-loader, style-loader. Sass requires sass-loader and sass to be installed
4. .png, .jpg, .gif url-loader
5. .svg svg-react-loader
6. * file-loader

Redwood's webpack configuration comes with postcss-loader. It's ready to plug in your postcss-loader config, ./web/config/postcss.config.js:

// ./web/config/postcss.config.js

module.exports = {
    plugins: {
        'autoprefixer': {},
    }
}

# Configuring Webpack

We've made it easy to get started configuring webpack with the webpack setup command:

yarn rw setup webpack

This command sets up the right file (webpack.config.js) in the right place (web/config):

// web/config/webpack.config.js

module.exports = (config, { mode }) => {
  if (mode === 'development') {
    // Add dev plugin
  }

  // Add custom rules for your project
  // config.module.rules.push(YOUR_RULE)

  // Add custom plugins for your project
  // config.plugins.push(YOUR_PLUGIN)

  return config
}

# Examples

If you've never configured webpack before, here's some Redwood-specific examples to get you started.

# Changing the Title of the Page

By default, the title of the page will be the same as your app's base directory. For example, if your app's base directory is redwood-app, you'll see "redwood-app":

rw-wp-before

This is set in webpack.common.js:

// redwood/packages/core/config/webpack.common.js

new HtmlWebpackPlugin({
  title: path.basename(redwoodPaths.base),  template: path.resolve(redwoodPaths.base, 'web/src/index.html'),
  inject: true,
  chunks: 'all',
}),

To change this, in your web/config/webpack.config.js, search config's plugins array for HtmlWebpackPlugin and change it's title option:

// ./web/config/webpack.config.js

module.exports = (config, { env }) => {
  config.plugins.forEach((plugin) => {
    if (plugin.constructor.name === 'HtmlWebpackPlugin') {
      plugin.options.title = 'Some Custom Title'    }
  })

  return config
}

Now, back in the browser, you'll see:

rw-wp-after

Couldn't I just have done this in web/index.html?

Yep. And you should. But hey, you're learning how to configure webpack over here!

# Adding Tailwind CSS

This section is inspired by mdv.io's excellent blog post, Adding Tailwind CSS to RedwoodJS. Note that the webpack.config.js file is no longer necessary since Redwood's webpack configuration now comes with postcss-loader by default (see Supported Extensions and Loaders). Neither is PurgeCSS, since, as of Tailwind CSS v1.4, it's built-in.

But I need to use Tailwind right now

We hear you! And that's why we made the Tailwind CSS setup command:

yarn rw setup tailwind

First, install the development dependencies:

cd web
yarn add -D postcss-loader tailwindcss autoprefixer

As mentioned, we don't have to tell webpack to use postcss-loader. But we do have to configure it:

mkdir config
touch config/postcss.config.js
// ./web/config/postcss.config.js

const path = require('path')

module.exports = {
  plugins: [
    require('tailwindcss')(path.resolve(__dirname, '../tailwind.config.js')),
    require('autoprefixer')
  ],
}

So is postcss-loader a rule or a package or a...

We've used the word "postcss-loader" three times, and it's because there's actually three different things: 1) the postcss-loader "rule" in webpack, which is there by default, 2) the postcss-loader package, and 3) the configuration for the postcss-loader rule, which is what goes in postcss.config.js.

Are you sure you don't want to just use that setup command?

Now, initialize tailwind:

yarn tailwindcss init

This generates the tailwind config file, tailwind.config.js. Note that we'd ordinarily move this file to web/config, like we did with postcss.config.js. But since the Tailwind CSS IntelliSense won't work unless tailwind.config.js is in a base directory like web, we're just leaving this one here for now.

Finally, use the tailwind directives in web/src/index.css

/* ./web/src/index.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

And that should be it!

# Enabling Sass

Support for Sass is already configured, so all you have to do is install the development dependencies:

cd web
yarn add -D sass-loader sass

# Webpack Dev Server

Redwood uses Webpack Dev Server for local development. When you run yarn rw dev, TOML keys in your redwood.toml's [web] table, like port and apiProxyPath, are used as Dev Server settings, in this case, devServer.port and devServer.proxy respectively. You can see all the settings used for Redwood dev in webpack.development.js#L12-L32

# Pass settings with --forward

While it's possible to override Dev Server config with a file, it's often simpler to pass options with the yarn rw dev command using the --forward flag. See the Redwood CLI Doc for help and examples.

For the full list of Webpack Dev Server options, see this document.

# Example: Set Port and Disable Browser Opening

You can override redwood.toml settings:

yarn rw dev --forward="--port=1234 --open=false"

This will run your application's Web client on port 1234 and disable automatic browser window opening.

# Example: Allow External Host Access

If you're running Redwood in dev mode and try to test your application from an external source (i.e. outside your network), you'll get “Invalid Host Header”. To enable this workflow, you can run the following:

yarn rw dev --forward="--disable-host-check --host 0.0.0.0 --public example.company.com"

This runs the application and forwards to example.company.com.