scratch-webpack-configuration/README.md
2024-03-18 11:25:13 -07:00

156 lines
5.6 KiB
Markdown

# scratch-webpack-configuration
Shared configuration for Scratch's use of webpack
## Usage
Add something like this to your `webpack.config.*js` file:
```javascript
import ScratchWebpackConfigBuilder from 'scratch-webpack-configuration';
const builder = new ScratchWebpackConfigBuilder(
{
rootPath: __dirname,
enableReact: true
})
.setTarget('browserslist')
.addModuleRule({
test: /\.css$/,
use: [/* CSS loaders */]
})
.addPlugin(new CopyWebpackPlugin({
patterns: [/* CopyWebpackPlugin patterns */]
});
if (process.env.FOO === 'bar') {
builder.addPlugin(new MyCustomPlugin());
}
module.exports = builder.get();
```
Call `addModuleRule` and `addPlugin` as few or as many times as needed. If you need multiple configurations, you can
use `clone()` to share a base configuration and then add or override settings:
```javascript
const baseConfig = new ScratchWebpackConfigBuilder({rootPath: __dirname, libraryName: 'my-library'})
.addModuleRule({
test: /\.foo$/,
use: [/* FOO loaders */]
});
const config1 = baseConfig.clone()
.setTarget('browserslist')
.merge({/* arbitrary configuration */})
.addPlugin(new MyCustomPlugin('hi'));
const config2 = baseConfig.clone()
.setTarget('node')
.addPlugin(new MyCustomPlugin('hello'));
module.exports = [
config1.get(),
config2.get()
];
```
## What it does
- Sets up a default configuration that is suitable for most Scratch projects
- Use `enableReact` to enable React support
- Target `node` or `browserslist` (more targets will be added as needed)
- Adds `babel-loader` with the `@babel/preset-env` preset
- Adds `@babel/preset-react` if React support is enabled
- Adds target-specific presets for `webpack` 5's `externals` and `externalsPresets` settings
- Target-specific output directory under `dist/`
- `browserslist` builds to `dist/web/`
- `node` builds to `dist/node/`
- Supports merging in arbitrary configuration with `merge({...})`
### Asset Modules
This configuration makes webpack 5's [Asset Modules](https://webpack.js.org/guides/asset-modules/) available through
resource queries parameters:
```js
import myImage from './my-image.png?asset'; // Use `asset` (let webpack decide)
import myImage from './my-image.png?resource'; // Use `asset/resource`, similar to `file-loader`
import myImage from './my-image.png?inline'; // Use `asset/inline`, similar to `url-loader`
import myImage from './my-image.png?source'; // Use `asset/source`, similar to `raw-loader`
```
You can also use `file` for `asset/resource`, `url` for `asset/inline`, and `raw` for `asset/source`, to make it clear
which loader you're replacing.
## API
### `new ScratchWebpackConfigBuilder(options)`
Creates a new `ScratchWebpackConfigBuilder` instance.
#### `options`
Required:
- `rootPath` (string, required): The root path of the project. This is used to establish defaults for other paths.
Optional:
- `distPath` (string, default: `path.join(rootPath, 'dist')`): The path to the output directory. Defaults to `dist`
- `enableReact` (boolean, default: `false`): Whether to enable React support. Adds `.jsx` to the list of extensions
to process, and adjusts Babel settings.
- `libraryName` (string, default: `undefined`): If set, configures a default entry point and output library name.
under the root path.
- `srcPath` (string, default: `path.join(rootPath, 'src')`): The path to the source directory. Defaults to `src`
under the root path.
## Recommended Configuration
### Package exports
_The `exports` field in `package.json`_
Most `project.json` files specify a `main` entry point, and some specify `browser` as well. Newer versions of Node
support the `exports` field as well. If both are present, `exports` will take precedence.
For more information about `exports`, see: <https://webpack.js.org/guides/package-exports/>, especially the "Target
environment" section.
Unfortunately, plenty of tools don't support `exports` yet, and some that do exhibit some surprising quirks.
Here's what I currently recommend for a project with only one entry point:
```json
{
"main": "./dist/node/foo.js",
"browser": "./dist/web/foo.js",
"exports": {
"webpack": "./src/index.js",
"browser": "./dist/web/foo.js",
"node": "./dist/node/foo.js",
"default": "./src/index.js"
},
}
```
- `main` supports older Node as well as `jest`
- `browser` is present for completeness; I haven't found it strictly necessary
- `exports.webpack` is the entry point for Webpack
- `webpack` will grab the first item under `exports` matching its conditions, including `browser`, so I recommend
listing `exports.webpack` first in the `exports` object
- this allows (for example) `scratch-gui` to build `scratch-vm` from source rather than using the prebuilt version,
resulting in more optimal output and preventing version conflicts due to bundled dependencies
- `exports.default` makes `eslint` happy
- `exports.browser` and `exports.node` prevent `exports`-aware tools from using `exports.default` for all contexts
Note that using `src/index.js` for the `webpack` and `default` exports means that the NPM package must include `src`.
### `browserslist` target
While it could be handy to include `browserslist` configuration in this package, there are tools other than `webpack`
that should use the same `browserslist` configuration. For that reason, I recommend configuring `browserslist` in
your `package.json` file or in a top-level `.browserslistrc` file.
The Scratch system requirements determine the browsers we should target. That information can be found here:
<https://scratch.mit.edu/faq>