I'm having an issue importing a component from one React project into another. The problems seems very basic but I'm having a really hard time figuring out where the problem is and what is the exact craco configuration to achieve my goal.
Exporting project
I'm exporting App
, which is a functional React component.
src/index.js
import App from "./App";
export default App;
I'm using craco mainly because of Tailwindcss and antd, this is the configuration file:
craco.config.js
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
const WebpackBar = require("webpackbar");
const CracoAntDesignPlugin = require("craco-antd");
const path = require("path");
module.exports = {
style: {
postcss: {
plugins: [require("tailwindcss"), require("autoprefixer")],
},
},
webpack: {
plugins: [
new WebpackBar({ profile: true }),
...(process.env.NODE_ENV === "development"
? [new BundleAnalyzerPlugin({ openAnalyzer: false })]
: []),
],
configure: (webpackConfig, { env, paths }) => {
paths.appBuild = webpackConfig.output.path = path.resolve("dist");
webpackConfig.output = {
...webpackConfig.output,
filename: "index.bundle.js",
path: path.resolve(__dirname, "dist"),
library: "library",
libraryTarget: "umd",
};
webpackConfig.entry = path.join(__dirname, "./src/index.js");
return webpackConfig;
},
},
plugins: [
{
plugin: CracoAntDesignPlugin,
options: {
customizeThemeLessPath: path.join(
__dirname,
"./src/styles/variables.less"
),
lessLoaderOptions: {
lessOptions: {
javascriptEnabled: true,
},
},
},
},
],
};
I'm using npm to publish my package and import it in the other project. This is the package.json start configuration (infos removed for privacy):
package.json
{
"name": [company-repo-name],
"version": "1.1.1-alpha16",
"homepage": ".",
"repository": [company-repo],
"main": "dist/index.bundle.js",
"publishConfig": {
"registry": [company-registry]
},
...
npm run build
works as intended and generate a index.bundle.js
inside the dist folder. I'm not sure if the problem lies here, but the file is full of minified functions and doesn't seem to export anything.
Consumer project
Installing the exporting project via npm works fine, and trying to import the App
component gives me no result:
import App from [company-repo-name];
gives me {}
(empty object)import { App } from [company-repo-name];
gives me undefined
I currently don't know where the problem lies and I'm looking forward for suggestions to try out.
To import component outside src/ directory with React, we can declare a local dependency on package. json. { //... "dependencies": { "app-b-dashboard": "file:./packages/app-b-dashboard" //... } //... } to declare the app-b-dashboard dependency in the dependencies section of package.
CRACO stands for Create-React-App Configuration Override. It is implemented as an easy way to override create-react-app configuration without mastering Webpack or ejecting.
So after days fiddling with the webpack configurations I came across this life saver article. The thing I didn't try was the first thing the article says: "Output a single bundle instead of chunks". The lines that did the trick included changing the optimization webpack configuration:
config.optimization.splitChunks = {
cacheGroups: {
default: false,
},
};
config.optimization.runtimeChunk = false;
After following all the steps presented in the article, I ended up with the craco webpack configuration looking like this:
configure: (config, { paths }) => {
paths.appBuild = config.output.path = path.resolve("build");
if (process.env.REACT_APP_INJECTABLE === "true") {
config = disableChunks(config);
config = makeInjectable(config, { paths });
}
return config;
}
disableChunks()
was imported from a secondary file that consolidated the build in a single bundle. I also disabled the minimization so I could have more descriptive errors in my consumer project. This is disable-chunks.js
:
module.exports = function disableChunks(config) {
// Consolidate bundle instead of chunk
// https://webpack.js.org/plugins/split-chunks-plugin
config.optimization.splitChunks = {
cacheGroups: {
default: false,
},
};
// Move runtime into bundle instead of separate file
// https://webpack.js.org/configuration/optimization
config.optimization.runtimeChunk = false;
config.optimization.minimize = false;
// JS
// https://webpack.js.org/configuration/output
config.output.filename = "main.js";
// CSS
// https://webpack.js.org/plugins/mini-css-extract-plugin
const cssPluginIdx = config.plugins
.map((p) => p.constructor.name)
.indexOf("MiniCssExtractPlugin");
if (cssPluginIdx !== -1) {
config.plugins[cssPluginIdx].options.filename = "main.css";
}
return config;
};
The last configuration file is make-injectable.js
that sets the output configuration. I has this configured before but decided to move it to another file for organization reasons.
module.exports = function makeInjectable(config, { paths }) {
// Output a UMD module and define its name via the library key.
// This key will be what is referenced when the hub looks for
// the correct module to dynamically load after the bundle is
// injected into the DOM
// https://webpack.js.org/configuration/output
config.output.library = basename(process.env.npm_package_name);
config.output.libraryTarget = "umd";
// Set separate entry point when building the injectable lib
// https://webpack.js.org/concepts/entry-points
config.entry = `${paths.appSrc}/index.injectable.js`;
// Exclude shared dependencies to reduce bundle size
// https://webpack.js.org/configuration/externals
config.externals = {
react: "react",
"react-router-dom": "react-router-dom",
};
return config;
};
Again, the code that worked for my was basically copied from the article Implementing a Micro-Frontend Architecture With React by J.C. Yamokoski (if you come across this question, thank you my man).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With