Im trying to build out a micro frontend for the first time so my main application can support a sub application. I have it all working when everything is just rendering App.tsx (remote) but as soon as I try and render a child within the remote application I get the Cannot find module error from webpack
Container craco.congig.js
/* eslint-disable #typescript-eslint/no-var-requires */
const CracoEsbuildPlugin = require('craco-esbuild');
const { ModuleFederationPlugin } = require("webpack").container;
const deps = require("./package.json").dependencies;
module.exports = {
webpack: {
plugins: {
add: [
new ModuleFederationPlugin({
name: "Dashboard",
remotes: {
DigitalCanopy: "DigitalCanopy#//localhost:3001/remoteEntry.js",
},
shared: {
react: {
singleton: true,
strictVersion: true,
requiredVersion: deps['react']
},
"react-dom": {
singleton: true,
strictVersion: true,
requiredVersion: deps['react-dom']
},
},
}),
],
},
...
My remote craco.config.js
/* eslint-disable #typescript-eslint/no-var-requires */
const CracoEsbuildPlugin = require('craco-esbuild');
const { ModuleFederationPlugin } = require("webpack").container;
const deps = require("./package.json").dependencies;
module.exports = {
devServer: {
port: 3001
},
webpack: {
plugins: {
add: [
new ModuleFederationPlugin({
name: "DigitalCanopy",
exposes: {
"./DigitalCanopy": "./src/App.tsx",
},
filename: "remoteEntry.js",
shared: {
react: { singleton: true },
"react-dom": { singleton: true },
},
}),
],
},
configure: (webpackConfig) => ({
...webpackConfig,
output: {
...webpackConfig.output,
publicPath: "auto",
},
}),
},
plugins: [
{
plugin: CracoEsbuildPlugin,
options: {
esbuildLoaderOptions: {
// Optional. Defaults to auto-detect loader.
loader: 'tsx', // Set the value to 'tsx' if you use typescript
target: 'es2018',
},
esbuildMinimizerOptions: {
target: 'es2018',
css: true, // if true, OptimizeCssAssetsWebpackPlugin will also be replaced by esbuild.
},
skipEsbuildJest: false, // Optional. Set to true if you want to use babel for jest tests,
esbuildJestOptions: {
loaders: {
'.ts': 'ts',
'.tsx': 'tsx',
},
},
},
},
],
};
My remote App.tsx
import { createTheme, ThemeProvider } from '#mui/material';
import React from 'react';
import './App.css';
import App1 from './App1';
const baseTheme = createTheme({
...MUI THEME STUFF
});
function App() {
return (
<ThemeProvider theme={baseTheme}>
<div className="App">Digital Canopy App</div>;
<App1 />
</ThemeProvider>
);
}
export default App;
This works and renders fine until I try and render <App1 />
Then I get this error Module not found: Error: Can't resolve './App1' in ...
Any ideas? I feel like this should just work. Importing children components from within the remote is pretty standard doesnt seem unique but I cannot find anything similar online which makes me think Im missing something obvious.
Thanks for the help
My issue was I was missing the .tsx extension on the import. I have no idea why that is required by the sub application. My build configs are identical for typescript and my main app does not require that. I'll dig in and try and figure out why
Related
I am building a project using Vite + React + Antd.
My project has lodash library, when i build with vite build command then get an error like below:
Running on environment production
vite v2.9.9 building for production...
transforming (2741) node_modules\.pnpm\lodash#4.17.21\node_modules\lodash\isLength.jsUnexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs) load "\u0000cross-fetch?commonjs-proxy"
error during build:
Error: Unexpected early exit. This happens when Promises returned by plugins cannot resolve. Unfinished hook action(s) on exit:
(commonjs) load "\u0000cross-fetch?commonjs-proxy"
In my vite.config.js file, I added #rollup/plugin-commonjs,
import commonjs from '#rollup/plugin-commonjs';
import react from '#vitejs/plugin-react';
import { defineConfig, loadEnv } from 'vite';
export default ({ mode }) => {
const env = loadEnv(mode, 'env');
const htmlPlugin = () => {
return {
name: 'html-transform',
// Replace %VITE_X% env variables in index.html.
transformIndexHtml(html: string) {
return html.replace(/%(.*?)%/g, function match(_match, p1) {
return env[p1];
});
},
};
};
return defineConfig({
resolve: {
alias: [
{ find: /^~/, replacement: '' },
{ find: 'react/jsx-runtime', replacement: 'react/jsx-runtime.js' },
],
},
define: {
'process.env': process.env,
},
build: {
outDir: './build',
rollupOptions: {
plugins: [commonjs()],
},
commonjsOptions: {
exclude: [/./],
},
},
publicDir: './public',
css: {
preprocessorOptions: {
less: {
javascriptEnabled: true,
},
},
},
optimizeDeps: {
include: ['#ant-design/icons'],
},
plugins: [
htmlPlugin(),
react({
babel: {
plugins: [['#babel/plugin-transform-react-jsx', { runtime: 'automatic' }]],
},
}),
],
});
};
I tried to change lodash into lodash-es, but in my node_modules has a couple of libraries use it.
Please help me. Thank all
I am making a react app with vite instead of creat react app. When I use .jsx as suffix, it works fine. But when I use .js, throws hundreds of errors in my files, such as:
Layout.js:131:9: error: Unexpected "<"
I've read this in twitter from Evan You but is there no way?
As far as I used this code in vite.config.ts file:
import { defineConfig } from 'vite'
export default defineConfig(() => ({
esbuild: {
loader: 'jsx',
},
optimizeDeps: {
esbuildOptions: {
loader: {
'.js': 'jsx',
},
},
},
})
but it still didn't work! Could you possibly help me?
Try the below Vite configuration. This configuration worked for me. But in every js file, need to import React.
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
import { resolve } from 'path';
import fs from 'fs/promises';
// https://vitejs.dev/config/
export default defineConfig({
resolve: {
alias: {
src: resolve(__dirname, 'src'),
},
},
esbuild: {
loader: 'jsx',
include: /src\/.*\.jsx?$/,
exclude: [],
},
optimizeDeps: {
esbuildOptions: {
plugins: [
{
name: 'load-js-files-as-jsx',
setup(build) {
build.onLoad(
{ filter: /src\\.*\.js$/ },
async (args) => ({
loader: 'jsx',
contents: await fs.readFile(args.path, 'utf8'),
})
);
},
},
],
},
},
plugins: [react()],
});
I couldn't find any information on how to make #emotion/react work in Storybook when using Vite as a bundler in a React application.
I'm getting errors like Invalid value for prop 'css' in <div> tag in almost every story.
Even though, #emotion/react is working fine for the webapp itself.
Here's my vite.config.js configuration:
import { defineConfig } from 'vite';
import react from '#vitejs/plugin-react';
export default defineConfig({
esbuild: {
jsxFactory: 'jsx',
jsxInject: `import { jsx } from '#emotion/react'`,
},
plugins: [
react({
jsxImportSource: '#emotion/react',
babel: {
plugins: ['#emotion/babel-plugin'],
},
}),
],
});
And here's my main.js for Storybook:
const svgrPlugin = require('vite-plugin-svgr');
module.exports = {
core: {
builder: 'storybook-builder-vite',
},
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.#(js|jsx|ts|tsx)'],
addons: ['#storybook/addon-links', '#storybook/addon-essentials'],
viteFinal: (config, { configType }) => {
config.define = {
'window.process': {
env: {
NODE_ENV: configType.toLowerCase(),
},
},
};
return {
...config,
plugins: [
...config.plugins,
svgrPlugin({
svgrOptions: {
icon: true,
},
}),
],
};
},
};
The solution was found in storybook-builder-vite's github page here.
It is a project composed of Vite & React & antd.
I want to handle antd theme dynamically in vite.config.ts.
I would appreciate it if you could tell me how to modify less.modifyVars value in React component.
This is the current screen.
light state /
dark state
In dark mode, the style of the select component does not work properly.
import { getThemeVariables } from 'antd/dist/theme'
...
css: {
modules: {
localsConvention: 'camelCaseOnly'
},
preprocessorOptions: {
less: {
javascriptEnabled: true,
modifyVars: {
...getThemeVariables({
dark: true // dynamic
})
}
}
}
}
}
You need to import 'antd/dist/antd.less' instead of 'antd/dist/antd.css'
Install dependency for less npm add -D less. Vite will automatically catch it.
Use the following config:
css: {
preprocessorOptions:{
less: {
modifyVars: {
'primary-color': '#1DA57A',
'heading-color': '#f00',
},
javascriptEnabled: true,
},
},
},
It's been a while, but this is works for me now:
You need to make sure you import less on demand. I use plugin vite-plugin-imp to achieve. And then getThemeVariables should be work well.
import vitePluginImp from 'vite-plugin-imp';
import { getThemeVariables } from 'antd/dist/theme';
export default defineConfig({
plugins: [
// ...
vitePluginImp({
libList: [
{
libName: 'antd',
style: (name) => `antd/es/${name}/style`,
},
],
}),
],
resolve: {
alias: [
// { find: '#', replacement: path.resolve(__dirname, 'src') },
// fix less import by: #import ~
// https://github.com/vitejs/vite/issues/2185#issuecomment-784637827
{ find: /^~/, replacement: '' },
],
},
css: {
preprocessorOptions: {
less: {
// modifyVars: { 'primary-color': '#13c2c2' },
modifyVars: getThemeVariables({
dark: true,
// compact: true,
}),
javascriptEnabled: true,
},
},
},
});
Moreover: you can get more inspiration from here: vite-react/vite.config.ts
I'm trying to get Webpack Module Federation working with a NextJS app where the federated module is using styled-components. My configuration is working as expected if I'm only using react and react-dom but using styled-components gives me these errors:
It looks like there are several instances of 'styled-components' initialized in this application. This may cause dynamic styles to not render properly, errors during the rehydration process, a missing theme prop, and makes your application bigger without good reason.
and
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
I have tried the different approaches to resolve styled-components to a single instance by modifying the Webpack config in both the host and remote apps, but all seem to fail.
Here is my current configuration:
Federated modules repo (webpack.config.js):
const { ModuleFederationPlugin } = require("webpack").container;
const deps = require("./package.json").dependencies;
const path = require("path");
module.exports = {
mode: "development",
devServer: {
contentBase: path.join(__dirname, "dist"),
port: 3001,
},
output: {
publicPath: "auto",
},
resolve: {
extensions: [".js"],
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
plugins: [
["babel-plugin-styled-components", { pure: true, ssr: true }],
],
presets: ["#babel/preset-react"],
},
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "remoteLib",
filename: "remoteEntry.js",
exposes: {
"./Button": "./src/Button",
},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
"styled-components": {
singleton: true,
requiredVersion: deps["styled-components"],
},
},
}),
],
};
Consuming NextJS app Webpack config (next.config.js):
webpack: (config, options) => {
const { ModuleFederationPlugin } = options.webpack.container;
config.plugins.push(
new ModuleFederationPlugin({
remotes: {
'federated-components': 'remoteLib#http://localhost:3001/remoteEntry.js'
}
})
);
return config;
}