Custom component builds

If needed, you can customize the CLI's webpack settings, precompile your source files or provide a completely custom build of your components. You do not normally need to modify your component source code for Interplay.

In this article

Default CLI build behaviour

The Interplay CLI uses webpack to bundle your code source code packages with a default set of loaders and plugins.

The default behaviour is to use the  build value in your interplay.config.js package settings as the entry point for and bundling each package. (If no build settings is provided, the src value will be used for both parsing and bundling)

//interplay.config.js 
{ 
"framework": "react", 
"packages": [ { 
	"name": "your-package",
 	"packagePath": "package.json", 
	"src": "src/index.js" 		//entry point for parsing 
	"build": "src/index.js" 	//entry point for bundling 
} ] 
}

You can customize the build process using one of the following 3 approaches.

1. Customizing the CLI's webpack config

In some cases you may want to modify the webpack config that the CLI uses to bundle your index file defined in your  interplay.json file. You can do this by defining a webpackConfig modifier function in your interplay.config.js file as shown below. This function is called immediately before calling webpack.

Example - modifying an individual webpack loader configuration:

//interplay.config.js
module.exports = { 
	modifiers: { 
		/** 
		*@param config - the webpack config used by the CLI 
		*@param webpack - the instance of webpack 
		*/ 
		webpackConfig: (config, webpack) => { 
			//see existing loader rules 
			config.module.rules.map((rule) => { console.log(rule); }); 

			//Find the sass loader config 
			const sassRule = config.module.rules.find((rule) => { 
				return rule.test.source == "\.sass$"); 
			}); 
			//set our custom sass loader config here 
			sassRule.use = [ ] 

			return config; 
		}, 
}, };

Example - replace all of the CLI's default loader rules with our own:

//interplay.config.js
const myCustomWebpackConfig = require("./custom/config"); 
module.exports = { 
	modifiers: { 
		webpackConfig: (config, webpack) => { 
			config.module.rules = myCustomWebpackConfig.module.rules; 
			return config; 
	}, 
}, };

When modifying the default webpack config, leave the "entry" and "output" values unchanged. This ensures the CLI will find the files it expects.

2. Precompiling your source files

Instead of allowing the CLI to compile your source code, you can use your own process to compile your individual files. Typically you may have a custom build script that handles your CSS pre-processing, or uses babel to transpile javascript files.

As a simple example, you might use the @babel/cli to transpile your directory of code, including your index file.

babel src --out-dir dist 
Successfully compiled 106 files with Babel.

In this example babel picks up its config from the local babel configuration file such as .babelrc or babel.config.js and transpiles each file in the  src directory to an equivalent file in the dist directory. This includes the src/index.js file, which is transpiled to dist/index.js

You can then tell Interplay to use your transpiled files as the build entrypoint by adding a  build setting to interplay.config.js for each package that points to your compiled index instead of your source index:

//interplay.config.js 
{ "framework": "react", 
	"packages": [ 
	{ 
		"name": "your-package", 
		"packagePath": "package.json", 
		"src": "src/index.js", //parsing entry point 
		"build": "dist/index.js". //bundling entry point
} 
] 
}

Here the CLI will still use  src/index.js as the entry point for parsing, but now it will use dist/index.js as the entrypoint for webpack bundling.

3. Providing a custom build

Alternatively you can create your own build of your components to use in Interplay.

To provide a custom build for a package, you set the  build setting for that package in interplay.config.js. There are two ways to use this:
  • Provide an alternate index entry file that the CLI should use for bundling e.g. dist/index.js. You can use this if your build process just transpiles your source but it still needs bundling by webpack for deploy (as in 2 above), or if your build process outputs a commonjs build that needs bundling into a UMD bundle for the browser.
  • Provide an array of the files that make up your custom build, in the order that interplay should just include them on the page e.g. ['dist/vendors.js','dist/chunk1.js', 'dist/chunk2.js','dist/bundle.js' ] When you run the CLI you should see these files being deployed to Interplay. (Requires CLI version 2.1+).
In both cases the custom build must use the same component export names as the  src entrypoint for parsing, but the build can contain additional exports. This can happen where you have a DS build containing everything but want to use a custom  src index with only a subset of the exports to parse into Interplay.
Remember that to see any code changes in Interplay, you will need to run your custom build first, then run the CLI to use your updated build.
Example: manually creating a custom build with webpack

Here is an example webpack config will create a UMD bundle, using `./src/index.js` as the entrypoint.

//custom.webpack.config.js
const path =require('path'); 
module.exports = () => ({ 
	mode: 'production', 
	entry: './src/index.js', //your component index path 
	output: { path: path.join(process.cwd(), 'dist'),//output folder 
		filename: 'bundle.js',//output file name 
		libraryTarget: 'umd',//or commonjs or commonjs2 
	}, 
	module: { 
		rules: [ { 
			test: /.js$/, 
			use: { 
				loader: 'babel-loader', 
				options: { cacheDirectory: true }, 
			}, 
		}, 
		//add more loaders here if required for your files 
		], 
	}, 
	resolve: { alias: { //add any required aliases here } } 
	externals: { 
		react: { root: 'React', commonjs2: 'react', commonjs: 'react', amd: 'react', },
		'react-dom': { root: 'ReactDOM', commonjs2: 'react-dom', commonjs: 'react-dom', amd: 'react-dom', }, }, });

If we save this file as custom.webpack.config.js, we can run the webpack cli at the terminal prompt:

webpack-cli --config custom.webpack.config.js //output asset bundle.js 145 KiB [emitted] [minimized] (name: main) 1 related asset webpack 5.43.0 compiled successfully in 3477 ms

This creates a build at  dist/bundle.js, as specified in the output section of the webpack config above.

We can now tell the CLI to use this bundle by setting it as the entrypoint of the build:

//interplay.config.js 
{ 
"framework": "react", 
"packages": [ 
	{ "name": "your-package", 
	"relativePath": "package.json", 
	"src": "src/index.js", //parsing entry point 
	"build": "dist/bundle.js". //bundling entry point 
} ] }

Now when we run the CLI again...

interplay

...it will use  src/index.js as the entrypoint for parsing the component source, and use the dist/bundle.js as the build. If dist/bundle.js is a UMD file it will be deployed unchanged. If it is a commonjs or commonjs2 file the CLI will bundle it for deployment to the browser.

Troubleshooting builds

Isolating the component

As with most development issues, in general a good approach to troubleshooting build problems is to isolate the problem. For a component library build the simplest way to do this is to comment out components in your index file and run the build again, to work out which component is causing the problem:

// index.js 

// export Accordion from './Accordion'; 
// export AccordionToggle, { useAccordionToggle } from './AccordionToggle'; 
// export AccordionCollapse from './AccordionCollapse'; 
// export Alert from './Alert'; 
export Badge from './Badge'; 
// export Breadcrumb from './Breadcrumb'; 
// export BreadcrumbItem from './BreadcrumbItem';

File resolution/Module not found

If webpack reports "module not found" errors, it is usually because the module is not installed, or an alias is required to resolve it. You may need to create aliases in your interplay configuration if your code requires them.

The CLI uses node module resolution to find its way around your repo, starting with your component index file for each of the packages you are imported. Sometimes the CLI can't resolve a file. This is usually due to one of the following reasons:

1. Missing npm package

The CLI follows standard node resolution to resolve imports, 'finding up' through node_modules folders from the file where the import is declared.

  • Check that any required npm dependencies have been installed
  • Check that npm modules installation paths are what you expect. Sometimes we find that an index file has been created at a level above where the installed node_modules exists.
2. Missing alias

The CLI automatically generates aliases based on the package.json files found in your repo, but if you are using other custom aliases you'll need to tell Interplay about them. You can also override the CLI's default package aliases by defining them yourself.

To do this, add a top level node called 'alias' in the CLI's interplay.json configuration file and map the local path for each alias your code requires. This path should be relative to the working directory where you are running the CLI (usually the base folder of the repo).

//interplay.config.js 
"alias": { 
	"@Components": "./relative/path1/here/", //start with ./ 
	"@Alias2": "./relative/path2/here/", 
	"package-name-here": "./relative/path3/here/" 
},

Note that the mapped alias paths should begin "./" for relative paths.

These aliases will be used by the CLI when resolving code imports, and passed to webpack for use in bundling your code.

Please refer to the import settings documentation for more details.

3. package.json fields not set

When a code import resolves to a package name, the package.json is inspected for a main field.

  • Ensure that that a main field exists as expected in the package.json and it points to the path you expect
  • Sometimes the file specified in the main field does not yet exist locally. Ensure that any required build process for the package has been run first to generate expected local files before running the Interplay CLI.

Next: Continuous Integration (CI)