Building your components

👉

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.

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 src value in your interplay.config.js settings as the entry point for parsing and bundling each package:

//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.

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 an interplay.js file along side your interplay.json as shown below. This function is called immediately before calling webpack.

In this example we are modifying an individual loader configuration in the webpack config:

//interplay.js
module.exports = {
    modifiers: {
 /**
         *@paramconfig - the webpack config used by the CLI
         *@paramwebpack - 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 custom sass loader config here
            sassRule.use = [  ]
            return config;
        },
    },
};


In this example we replace all of the CLI's default loader rules with our own:

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


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

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.

npx 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 bundle your transpiled files by adding a build.entry to interplay.json 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.

Providing a custom build

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

Your bundle should:

  • be a UMDcommonjs or commonjs2 library
  • be a single file
  • have any shared peer dependencies defined as external to the build e.g. react, react-dom, emotion, styled-components

Here is an example webpack config that does this:

//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:

npx 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 wrap it as a UMD bundle for deployment to the browser.

Troubleshooting component builds

Approach

As with most development issues, in general a good approach to troubleshooting build problems is to isolate the problem.

For component library builds the simplest way to do this is to comment out components in your index file, to work out which component is causing the problem:

// 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';

Module not found error

If webpack reports "module not found" errors, it is usually because the module is not installed, or an alias is required to resolve it. Please refer to the File Resolution section below.

File resolution

👉

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 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.