# Buildtime Domain Model

## Build Artifacts

If you wish to use the Reactium SDK and hooks system to change the behavior of Gulp tasks or Webpack compilation for your plugin, you can use build-time DDD artifacts to register your behaviors.

### reactium-gulp.js

Reactium's build process is started and primarily controlled by Gulp tasks:

{% code title="Gulp tasks" %}

```bash
npx gulp --tasks

Tasks for ~/Reactium/gulpfile.js
├── apidocs
├── local
├── assets
├── preBuild
├─┬ build
│ └─┬ <series>
│   ├── preBuild
│   ├── ensureReactiumModules
│   ├── clean
│   ├── manifest
│   ├─┬ <parallel>
│   │ ├── markup
│   │ └── json
│   ├─┬ <parallel>
│   │ ├── assets
│   │ └── styles
│   ├── scripts
│   ├── umdLibraries
│   ├── serviceWorker
│   ├── compress
│   └── postBuild
├── compress
├── postBuild
├── postServe
├── clean
├── ensureReactiumModules
├── default
├── json
├─┬ manifest
│ └─┬ <series>
│   └─┬ <parallel>
│     ├─┬ <series>
│     │ ├── domainsManifest
│     │ └── mainManifest
│     ├── externalsManifest
│     └── umdManifest
├── domainsManifest
├── mainManifest
├── externalsManifest
├─┬ umd
│ └─┬ <series>
│   ├── umdManifest
│   └── umdLibraries
├── umdManifest
├── umdLibraries
├── markup
├── scripts
├── serve
├── serve-restart
├── serviceWorker
├─┬ sw
│ └─┬ <series>
│   ├── umd
│   └── serviceWorker
├── static
├── static:copy
├── styles:partials
├── styles:pluginAssets
├── styles:colors
├── styles:compile
├─┬ styles
│ └─┬ <series>
│   ├── styles:colors
│   ├── styles:pluginAssets
│   ├── styles:partials
│   └── styles:compile
├── watch
└── watchFork
```

{% endcode %}

As you can see above, there are many tasks performed with Gulp, and you may wish to create, change, or delete tasks that are run during the build, and this can be done with ease using the **reactium-gulp.js** artifact.

When you start the build (`npm run build` or `npm run local` for product or local development respectively), really you are invoking the `gulp` default task, which in turn will kick off a number of other tasks in series or in parallel.

{% hint style="info" %}
All built-in Gulp task are defined in **.core/gulp.tasks.js**
{% endhint %}

An abbreviated summary of the default gulp task starts a series of tasks as follows:

1. A stub **preBuild** task (does nothing, meant to be optionally implemented by your project)
2. Cleanup tasks to prepare the project directory (ensure **`reactium_modules`** directory exists, remove contents of public, ...)
3. Prepare a set of source manifests based on DDD artifacts found throughout your project.
4. Build static html markup and any generated json files
5. Process assets such as images, and compile CSS (using SASS)
6. Compile your application javascript with Webpack
7. Build any UMD (Universal Module Definition) files with Webpack
8. Create a Google Workbox service worker
9. Compress all compiled assets (for quicker delivery)
10. Generate [API docs](https://apidocjs.com/)
11. A stub **postBuild** task (does nothing, meant to be optionally implemented by your project)

{% code title="excerpt of gulp.tasks.js (default task)" %}

```javascript
    task('preBuild'),
    task('ensureReactiumModules'),
    task('clean'),
    task('manifest'),
    gulp.parallel(task('markup'), task('json')),
    gulp.parallel(task('assets'), task('styles')),
    task('scripts'),
    task('umdLibraries'),
    task('serviceWorker'),
    task('compress'),
    task('apidocs'),
    task('postBuild'),
```

{% endcode %}

{% hint style="info" %}
For those industrious folks, see **reactium\_modules/@atomic-reactor/reactium-core/gulp.tasks.js** for the full details of what gulp tasks are defined in core.

See reactium-gulp section below for how to properly change these in your project.
{% endhint %}

#### ReactiumGulp

Prior to running any Gulp task, all of the tasks are registered to a global singleton **ReactiumGulp**, that is made available to any **reactium-gulp.js** file found in your project under:

* anywhere in the **src** directory (or any subdirectory)
* anywhere in the **reactium\_modules** directory

If a [reactium-gulp.js](https://apidocjs.com/) file is found anywhere in one of these location, it will be loaded during the initialization of Gulp prior to running any gulp task. Inside this file, you may register one or more Reactium Gulp synchronous hooks to change the behavior of the gulp build for the whole project.

| Hook       | Usage                                                                                                   |
| ---------- | ------------------------------------------------------------------------------------------------------- |
| **config** | Synchronous hook that provides the gulp configuration and webpack configuration prior to running tasks. |
| **tasks**  | Synchronous hook that provides the Registry (register, unregister) of each Gulp task prior to use.      |

{% hint style="info" %}
For example, say you do not wish to use the current Dart SASS compilation (defined in the .core/gulp.tasks.js in the **styles:compile** task, but instead which to replace this with node-sass. To do this, first you will want to register a synchronous **tasks** hook callback. This hook will be passed the task registry used to generate the full list of gulp tasks you see above. Use this registry to unregister the existing gulp task, and replace it with your own.
{% endhint %}

{% code title="reactium-gulp.js" %}

```
const gulp = require('gulp');
const sass = require('gulp-sass');
sass.compiler = require('node-sass');
const reactiumImporter = require('@atomic-reactor/node-sass-reactium-importer');
const jsonFunctions = require('node-sass-functions-json').default;
const sourcemaps = require('gulp-sourcemaps');
const gulpif = require('gulp-if');
const cleanCSS = require('gulp-clean-css');
const prefix = require('gulp-autoprefixer');
const rename = require('gulp-rename');
const env = process.env.NODE_ENV || 'development';
const isDev = env === 'development';
const browserSync = require('browser-sync');

ReactiumGulp.Hook.registerSync('tasks', (GulpRegistry, config) => {
    GulpRegistry.unregister('styles:compile');

    const compileStyles = () => {
        return gulp
            .src(config.src.style)
            .pipe(gulpif(isDev, sourcemaps.init()))
            .pipe(
                sass({
                    functions: Object.assign({}, jsonFunctions),
                    importer: reactiumImporter,
                    includePaths: config.src.includes,
                }).on('error', sass.logError),
            )
            .pipe(prefix(config.browsers))
            .pipe(gulpif(!isDev, cleanCSS()))
            .pipe(gulpif(isDev, sourcemaps.write()))
            .pipe(rename({ dirname: '' }))
            .pipe(gulp.dest(config.dest.style))
            .pipe(gulpif(isDev, browserSync.stream()));
    };

    GulpRegistry.register('styles:compile', {
        task: compileStyles,
        order: 100,
    });
});
```

{% endcode %}

{% hint style="info" %}
You might also wish to change the values specified by **.core/gulp.config.js** that are used in your tasks. You can do this with the synchronous **config** hook.
{% endhint %}

{% code title="reactium-gulp.js" %}

```
// change the location where _colors.scss is generated by the
// styles:colors gulp task

ReactiumGulp.Hook.registerSync('config', gulpConfig => {
  gulpConfig.dest.colors = 'src/app/components/Admin/style/_colors.scss';
});
```

{% endcode %}

{% hint style="info" %}
This isn't the last or only way to manipulate the gulp tasks for your project. If you would prefer to get in between the final list of tasks that are used for gulp, you may wish to create a [gulp.tasks.override.js file.](https://docs.reactium.io/reactium-guides/reactium-core#gulp-tasks-override-js) Either method is fine, however **gulp.tasks.override.js** will simply export a function that returns the entire list of gulp tasks (including the **default**), and may invalidate other plugins' efforts from **reactium-gulp.js**. If you wish to play nice, use **reactium-gulp.js**
{% endhint %}

### reactium-webpack.js

When the Gulp **scripts** task is run, Gulp will run the Webpack compilation specified by the overridable configuration in **.core/webpack.config.js**. Likewise, when compiling any UMD (Universal Module Definition) javascript modules during the Gulp **umdLibraries** task, Gulp will run the Webpack compiliation specified by the overridable configuration provided in **.core/umd.webpack.config.js**.

#### ReactiumWebpack

Prior to running any either the main or umd Webpack compilations, the webpack configuration is run through a series of hooks that are registered to a global singleton **ReactiumWebpack**, that is made available to any **reactium-webpack.js** file found in your project under:

* anywhere in the **src** directory (or any subdirectory)
* in any node module directory located in a **reactium-plugin** directory
* anywhere in the **reactium\_modules** directory

If a [reactium-webpack.js](https://apidocjs.com/) file is found anywhere in one of these location, it will be loaded during the initialization of Webpack configuration prior to running any compilation. Inside this file, you may register one or more Reactium Webpack synchronous hooks to change the behavior of the webpack compilation for the whole project.

| Hook              | Usage                                                                                          |
| ----------------- | ---------------------------------------------------------------------------------------------- |
| **before-config** | Provides the **WebpackSDK** as an argument                                                     |
| **externals**     | Provide the **WebpackSDK**.externals registry, **WebpackSDK**.name, and **WebpackSDK**.context |
| **ignores**       | Provide the **WebpackSDK**.ignores registry, **WebpackSDK**.name, and **WebpackSDK**.context   |
| **rules**         | Provide the **WebpackSDK**.rules registry, **WebpackSDK**.name, and **WebpackSDK**.context     |
| **plugins**       | Provide the **WebpackSDK**.plugins registry, **WebpackSDK**.name, and **WebpackSDK**.context   |

{% hint style="info" %}
Note: most of the **WebpackSDK** registries (ignores, externals, rules, plugins) have an **sdk** property that refers back to the WebpackSDK object.
{% endhint %}

Both of the main webpack configuration and the umd configurations are built using a helper object, **WebpackSDK:**

#### WebpackSDK

This class provided the following public properties and methods, to aid in managing your Webpack configuration:

#### WebpackSDK setters

Most of the webpack configuration that is not terribly complex is handled with simple setters.

{% tabs %}
{% tab title="WebpackSDK.mode" %}
Setter for the webpack [**mode**](https://webpack.js.org/configuration/mode/) configuration property
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.mode = 'development'; // or production
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.entry" %}
Setter for the webpack [**entry**](https://webpack.js.org/configuration/entry-context/) configuration property
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.entry = {
  main: './src/app/main.js'
};
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.target" %}
Setter for webpack [**target**](https://webpack.js.org/configuration/target/) configuration property
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.target = 'web';
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.output" %}
Setter for webpack [**output**](https://webpack.js.org/configuration/output/) configuration property
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.output = {
  publicPath: '/assets/js/',
  path: path.resolve(__dirname, dest),
  filename: '[name].js',
};
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.devtool" %}
Setter for webpack [**devtool**](https://webpack.js.org/configuration/devtool/) configuration property
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.devtool = process.env.NODE_ENV === 'development' ? 'source-map' : '';
```

{% endtab %}
{% endtabs %}

#### WebpackSDK Methods

{% tabs %}
{% tab title="WebpackSDK.setCodeSplittingOptimize(env)" %}
Automatically configures the webpack [**optimization**](https://webpack.js.org/configuration/optimization/) configuration property, attempting to code-split Reactium javascript bundles into chunks that can be lazy loaded automatically by webpack, optimized to Reactium's logical components.

| Argument     | Type   | Description                   |
| ------------ | ------ | ----------------------------- |
| env          | String | 'development' or 'production' |
| {% endtab %} |        |                               |

{% tab title="Example" %}

```javascript
WebpackSDK.setCodeSplittingOptimize(process.env.NODE_ENV);
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.setWebpackDefaultOptimize(env)" %}
Automatically configures the webpack [**optimization**](https://webpack.js.org/configuration/optimization/) configuration property, attempting to code-split Reactium javascript bundles into chunks that can be lazy loaded automatically by webpack, in a way that is fairly default Webpack code-splitting behavior.

| Argument     | Type   | Description                   |
| ------------ | ------ | ----------------------------- |
| env          | String | 'development' or 'production' |
| {% endtab %} |        |                               |

{% tab title="Example" %}

```javascript
WebpackSDK.setWebpackDefaultOptimize(process.env.NODE_ENV);
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.setNoCodeSplitting(env)" %}
Automatically configures the webpack [**optimization**](https://webpack.js.org/configuration/optimization/) configuration property, setting up Reactium to bundle everything together in one monolithic bundle.

{% hint style="info" %}
To get this behavior for the top-level application entries, you can also start the build with the Environment Variable **DISABLE\_CODE\_SPLITTING** set to **'true'.**
{% endhint %}

| Argument     | Type   | Description                   |
| ------------ | ------ | ----------------------------- |
| env          | String | 'development' or 'production' |
| {% endtab %} |        |                               |

{% tab title="Example" %}

```javascript
WebpackSDK.setNoCodeSplitting(process.env.NODE_ENV)
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.addPlugin(pluginId, plugin)" %}
Used to register Webpack [**plugins**](https://v4.webpack.js.org/configuration/plugins/), and give them an id, so they can be overridden or removed.

| Argument | Type           | Description                                                              |
| -------- | -------------- | ------------------------------------------------------------------------ |
| pluginId | String         | Unique id of the webpack plugin instance, so that it can be manipulated. |
| plugin   | Webpack Plugin | Instance of a Webpack plugin                                             |

{% hint style="info" %}
Alternately, you can call register() on **WebpackSDK.plugins** (a standard Reactium registry). See **Using Registry** tab.
{% endhint %}
{% endtab %}

{% tab title="Example" %}

```
WebpackSDK.addPlugin('defines', new webpack.DefinePlugin({ foo: 'bar'}));
```

{% endtab %}

{% tab title="Using Registry" %}

```
WebpackSDK.plugins.register('defines', { 
  plugin: new webpack.DefinePlugin({ foo: 'bar'}),
});

// or unregister
WebpackSDK.plugins.unregister('defines');
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.addRule(ruleId, rule)" %}
Used to register Webpack [**module rules**](https://v4.webpack.js.org/configuration/module/#modulerules), but give them an id, so they can be easily overridden or removed.

| Argument | Type                                                                     | Description                          |
| -------- | ------------------------------------------------------------------------ | ------------------------------------ |
| ruleId   | String                                                                   | Your identifier for the module rule. |
| rule     | [**Webpack Rule**](https://v4.webpack.js.org/configuration/module/#rule) | A webpack rule object                |

{% hint style="info" %}
Alternately, you can call register() on **WebpackSDK.rules** (a standard Reactium registry). See **Using Registry** tab.
{% endhint %}
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.addRule('babel-loader', {
        test: [/\.jsx|js($|\?)/],
        exclude: [/node_modules/, /umd.js$/],
        resolve: {
            extensions: ['.js', '.jsx', '.json'],
        },
        use: [
            {
                loader: 'babel-loader',
            },
        ],
    });
```

{% endtab %}

{% tab title="Using Registry" %}

```javascript
WebpackSDK.rules.register('babel-loader', {
  rule: {
        test: [/\.jsx|js($|\?)/],
        exclude: [/node_modules/, /umd.js$/],
        resolve: {
            extensions: ['.js', '.jsx', '.json'],
        },
        use: [
            {
                loader: 'babel-loader',
            },
        ],
    },
});

// or to unregister
WebpackSDK.rules.unregister('babel-loader');
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.addIgnore(ignoreId, regExp)" %}
A special registry that manages the [**webpack.IgnorePlugin**](https://v4.webpack.js.org/plugins/ignore-plugin/), allowing you to easily specify regular expression that will instruct Webpack what sort of modules to ignore.

| Argument | Type   | Description                            |
| -------- | ------ | -------------------------------------- |
| ignoreId | String | Your identifier for the ignore pattern |
| regExp   | RegExp | Regular express pattern to ignore.     |

{% hint style="info" %}
Alternately, you can call register() on **WebpackSDK.ignores** (a standard Reactium registry). See **Using Registry** tab.
{% endhint %}
{% endtab %}

{% tab title="Example" %}

```javascript
WebpackSDK.addIgnore('sass', /\.sass$/);
```

{% endtab %}

{% tab title="Using Registry" %}

```javascript
WebpackSDK.ignores.register('sass', {
  test: /\.sass$/,
});

// or remove the ignore
WebpackSDK.ignores.unregister('sass');
```

{% endtab %}
{% endtabs %}

{% tabs %}
{% tab title="WebpackSDK.addContext(contextId, contextMap)" %}
A special registry that manages the **webpack.ContextReplacementPlugin**, allowing you to easily specify regular expression that will instruct Webpack what sort of modules to ignore.

| Argument   | Type   | Description                                                                             |
| ---------- | ------ | --------------------------------------------------------------------------------------- |
| contextId  | String | Your identifier for the webpack context                                                 |
| contextMap | Object | Object with **from** regex pattern to match and **to** path to map the webpack context. |

{% hint style="info" %}
Alternately, you can call register() on **WebpackSDK.plugins** (a standard Reactium registry), and register a new instance of the **webpack.ContextReplacementPlugin**. See **Using Registry** tab.
{% endhint %}
{% endtab %}
{% endtabs %}
