Configuring Modern.js

There are two configurations in the Modern.js, a compile configuration and a server runtime configuration.

The compile configuration can be configured in two places:

  • modern.config.(ts|js|mjs) file in the root path
  • package.json file
INFO

Configurations in both package.json and modern.config.ts file are not supported for the same configuration. Configuration in modern.config.ts is recommended.

Server runtime configuration can be configured in the modern.server-runtime.config.(ts|js|mjs) file in the root path.

Configure in the configuration file

Modern.js configuration files are defined in the root path of the project, and supports .ts, .js and .mjs formats:

  • modern.config.ts
  • modern.config.js
  • modern.config.mjs

We recommend using configuration files in .ts format, which provides friendly TypeScript type hints to help you avoid configuration errors.

Import the defineConfig tool function from @modern-js/app-tools, which will help you with configuration type derivation and type completion:

modern.config.ts
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig({
  source: {
    alias: {
      '@common': './src/common',
    },
  },
});

When using Rspack as the bundler, due to some differences in configuration types between webpack and Rspack, you need to specify <'rspack'> generic type for defineConfig:

modern.config.ts
- export default defineConfig({
+ export default defineConfig<'rspack'>({
   //...
});

modern.config.js

If you are developing a non-TypeScript project, you can use the configuration file in .js format:

modern.config.js
export default {
  source: {
    alias: opts => {
      opts['@common'] = './src/common';
    },
  },
};

You can also configure depending on your environment with process.env.NODE_ENV:

modern.config.js
export default {
  server: {
    ssr: process.env.NODE_ENV === 'development',
  },
};

Export Configuration Function

Modern.js supports exporting a function in the configuration file, and you can dynamically compute the configuration in the function and return it to Modern.js.

modern.config.js
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig(({ env, command }) => ({
  source: {
    alias: {
      '@foo': env === 'development' ? './src/foo.dev.ts' : './src/foo.prod.ts',
    },
  },
}));

This function takes the following parameters:

  • env: same as the value of process.env.NODE_ENV.
    • When running modern dev or modern start, the value of env is development.
    • When running modern build or modern serve, the value of env is production.
    • When running modern test, the value of env is test.
  • command: corresponds to the currently running command, such as dev, start, build, serve.

Export Async Function

Modern.js also supports exporting an asynchronous function in the configuration file, you can perform some asynchronous operations in the function:

modern.config.js
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig(async ({ env, command }) => {
  const result = await someAsyncFunction();

  return {
    html: {
      title: result,
    },
  };
});

Specify the Configuration File

You can specify the name of the configuration file using the --config option.

For example, if you need to use the modern.prod.config.js file when running build, you can add the following scripts to package.json:

package.json
{
  "scripts": {
    "dev": "modern dev",
    "build": "modern build --config modern.prod.config.js"
  }
}

You can also abbreviate the --config option to -c:

$ modern build -c modern.prod.config.js

In addition to configuration files, configuration options can also be set the modernConfig field in the package.json, such as:

package.json
{
  "modernConfig": {
    "source": {
      "alias": {
        "@common": "./src/common"
      }
    }
  }
}

Due to the limitation of the JSON file format, only simple types such as numbers, strings, boolean values, arrays, etc. can be defined in package.json. When we need to set the value of the function type, it is recommended to do so in the Modern.js configuration file.

Note

  • It is not recommended to use both package.json and modern.config.t[j]s for configuration. If both are used and a configuration conflict occurs, Modern.js will prompt error on the command line.
  • @modern-js/runtime exports the defineConfig API of the same name, please pay attention to the distinction.

Debug configuration locally

To facilitate local debugging configuration locally, Modern.js supports creating modern.config.local.(ts|js|mjs) files in the root directory of the project to override modern.config.(ts|js|mjs) configurations.

Example

For example, the port number is configured as 3000 in modern.config.ts:

modern.config.ts
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig({
  server: {
    port: 3000,
  },
});

If you need to change the port number to 3001 to debugging locally, but you don't want to change the modern.config.ts file of the current project, you can create a modern.config.local.ts file and add the following configuration:

modern.config.local.ts
import { defineConfig } from '@modern-js/app-tools';

export default defineConfig({
  server: {
    port: 3001,
  },
});

The configuration in the modern.config.local.ts file will be deep merged with the configuration in modern.config.ts and override the configurations in modern.config.ts, so server.port will be is overridden by 3001.

Note

When using modern.config.local.ts, please note the following:

  • The modern.config.local.ts file is only loaded when running modern dev or modern start commands, and will not be loaded when running modern build.
  • The modern.config.local.ts file overrides not only over modern.config.ts, but also the modernConfig field in package.json.
  • As modern.config.local.ts is only used for local debugging, it is not recommended to commit it to the repository, please ensure that the project's .gitignore file contains modern.config.local.ts.
.gitingore
modern.config.local.*

Merge Multiple Configurations

In some cases, you may need to merge multiple configurations into one configuration. You can use the mergeConfig util to merge multiple configurations.

The mergeConfig function accepts an array as a parameter, and each item in the array is a configuration object. mergeConfig will deeply merge each configuration object in the array, automatically merge multiple functions into an array, and returns a merged configuration object.

Example

modern.config.ts
import { mergeConfig } from '@modern-js/app-tools';

const config1 = {
   dev: {
     port: 3000,
   },
   tools: {
     postcss: () => console. log('config1');
   },
};
const config2 = {
   dev: {
     port: 3001,
   },
   tools: {
     postcss: () => console. log('config2');
   },
};

const mergedConfig = mergeConfig([config1, config2]);

In the above example, the merged configuration object is:

const mergedConfig = {
  dev: {
    port: 3001,
  },
  tools: {
    postcss: [() => console.log('config1'), () => console.log('config2')],
  },
};

Configuration Type

Modern.js exports AppUserConfig type, which corresponds to the type of Modern.js configuration object:

modern.config.ts
import type { AppUserConfig } from '@modern-js/app-tools';

const config: AppUserConfig = {
  tools: {
    webpack: {},
  },
};

When using Rspack as the bundler, due to some differences in configuration types between webpack and Rspack, you need to specify <'rspack'> generic type for defineConfig:

modern.config.ts
import type { AppUserConfig } from '@modern-js/app-tools';

const config: AppUserConfig<'rspack'> = {
  tools: {
    rspack: {},
  },
};