Shared configuration for Scratch's use of webpack
Add something like this to your webpack.config.*js file:
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:
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()
];- Sets up a default configuration that is suitable for most Scratch projects
- Use enableReactto enable React support
- Target nodeorbrowserslist(more targets will be added as needed)
 
- Use 
- Adds babel-loaderwith the@babel/preset-envpreset- Adds @babel/preset-reactif React support is enabled
 
- Adds 
- Adds target-specific presets for webpack5'sexternalsandexternalsPresetssettings
- Target-specific output directory under dist/- browserslistbuilds to- dist/web/
- nodebuilds to- dist/node/
 
- Supports merging in arbitrary configuration with merge({...})
This configuration makes webpack 5's Asset Modules available through resource queries parameters:
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.
Creates a new ScratchWebpackConfigBuilder instance.
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- .jsxto 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- srcunder the root path.
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:
{
  "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"
  },
}- mainsupports older Node as well as- jest
- browseris present for completeness; I haven't found it strictly necessary
- exports.webpackis the entry point for Webpack- webpackwill grab the first item under- exportsmatching its conditions, including- browser, so I recommend listing- exports.webpackfirst in the- exportsobject
- this allows (for example) scratch-guito buildscratch-vmfrom source rather than using the prebuilt version, resulting in more optimal output and preventing version conflicts due to bundled dependencies
 
- exports.defaultmakes- eslinthappy
- exports.browserand- exports.nodeprevent- exports-aware tools from using- exports.defaultfor all contexts
Note that using src/index.js for the webpack and default exports means that the NPM package must include src.
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