Vite - Multiple library entry points - reactjs

After a few hours, I managed to build my custom library with multiple entry points using vite.
I want to know if there is a better way to solve this problem.
// vite.config.ts
export default defineConfig({
plugins: [react()],
build: {
rollupOptions: {
input: {
index: resolve(__dirname, 'src/index.ts'),
hooks: resolve(__dirname, 'src/hooks.ts'),
},
external: [...Object.keys(peerDependencies), ...Object.keys(dependencies)],
output: [
{
dir: resolve(__dirname, 'dist'),
format: 'es',
entryFileNames: "[name].[format].js",
globals: {
react: 'React',
},
},
{
dir: resolve(__dirname, 'dist'),
format: 'cjs',
entryFileNames: "[name].[format].js",
globals: {
react: 'React',
},
}
],
},
sourcemap: true,
}
})
The build generate this files:

Related

After publish react in npm can't load chunks of react.lazy

I have a CRA react project where i'm using react.lazy to split the code. I'm currently working on publish it in npm as a react component.
For compilate the code i'm using Craco. Here is the configuration of it:
const CracoLessPlugin = require('craco-less');
const path = require('path');
const PACKAGE_NAME = 'name'
const CSS_FILE_NAME = 'main.css';
module.exports = {
webpack: {
configure: (webpackConfig, { paths }) => {
const buildFolder = path.resolve(__dirname, 'build');
paths.appBuild = buildFolder;
webpackConfig.externals = {
...webpackConfig.externals,
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDOM',
}
};
webpackConfig.plugins[5].options.filename = CSS_FILE_NAME;
webpackConfig.plugins[5].options.linkType = 'text/css'
return {
...webpackConfig,
output: {
...webpackConfig.output,
path: buildFolder,
filename: 'main.js',
library: PACKAGE_NAME,
libraryTarget: 'umd',
umdNamedDefine: true,
publicPath: `/`,
},
optimization: {
...webpackConfig.optimization,
runtimeChunk: false,
splitChunks: {
...webpackConfig.optimization.splitChunks,
chunks: 'all',
cacheGroups: {
default: false,
vendors: false,
},
},
},
};
},
},
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
javascriptEnabled: true,
}
}
}
]
};
I managed to publish it correctly but when i'm importing it in other react project, I can't manage to load the chunks. I always got something like this
This is happening for js and css files.
I think that the problem is related to the public_path of the output configuration of webpack, but i can't find the correct value for it to make this work.
I can give you more information about other related configuration if asked.
Thank you for the help.

SVGs and PNGs not loading

I am working on a micro frontend using Webpack.
And I have a problem where all local my SVGs and PNGs are not being loaded by Webpack5 react app. I keep getting 404 when doing that.
Can anyone point me out what I am doing wrong?
Here is the folder structuring
/public
/src
/components
navbar.tsx
/assets
Logo.svg
webpack.config.js
Here is my Webpack config. I am including the loader for assets, as indicated in the Webpack documentation
Webpack.config.js
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
const deps = require("./package.json").dependencies;
module.exports = {
output: {
publicPath: "http://localhost:3000/",
},
resolve: {
extensions: [".vue", ".tsx", ".ts", ".jsx", ".js", ".json"],
},
devServer: {
port: 3000,
historyApiFallback: true,
},
module: {
rules: [
{
test: /\.m?js/,
type: "javascript/auto",
resolve: {
fullySpecified: false,
},
},
{
test: /\.(css|s[ac]ss)$/i,
use: ["style-loader", "css-loader", "postcss-loader"],
},
{
test: /\.(ts|tsx|js|jsx)$/,
exclude: /node_modules/,
use: { loader: "babel-loader" },
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
],
},
plugins: [
new ModuleFederationPlugin({
name: "App1",
filename: "remoteEntry.js",
remotes: {},
exposes: {},
shared: {
...deps,
react: {
singleton: true,
requiredVersion: deps.react,
},
"react-dom": {
singleton: true,
requiredVersion: deps["react-dom"],
},
},
}),
new HtmlWebPackPlugin({
template: "./src/index.html",
}),
],
};
And here is one of the images imported in the Navbar.
Navbar.tsx
import React from "react";
export default function Navbar() {
return (
<img src="./assets/Logo.svg" alt="Logo" />
)
}
I'm not an expert in react but with the app rendered in App.js maybe your url img src should be something like src='./components/assets/ because it would start from the src folder ? (i know if it's an import it works as expected but here it's a src ..)
Feel free to delete i didn't have enough karma to comment

Webpack 5: Is it possible to output a javascript file non-bundled for configuration

I have a React TypeScript project that uses webpack 5.
I am trying to get a runtime-config.js file that I can change out in production by importing it as decribed in a similar Vuejs Docker issue.
I wanted to use File Loader but found that it's been deprecated in webpack 5
Here's what I want to achieve:
have ./runtime-config.js non bundled so that I can refer to it on the window object
easily reference that file in React (TypeScript) so that this dynamic configuration can be read.
Any help is appreciated.
Below is my webpack configuration:
// webpack.config.js
import path from 'path'
import { Configuration as WebpackConfiguration, DefinePlugin, NormalModuleReplacementPlugin } from 'webpack'
import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin'
import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'
import ESLintPlugin from 'eslint-webpack-plugin'
import tailwindcss from 'tailwindcss'
import autoprefixer from 'autoprefixer'
const CopyPlugin = require('copy-webpack-plugin');
interface Configuration extends WebpackConfiguration {
devServer?: WebpackDevServerConfiguration;
}
const config: Configuration = {
mode: 'development',
target: 'web',
devServer: {
static: path.join(__dirname, 'build'),
historyApiFallback: true,
port: 4000,
open: true,
liveReload: true,
},
output: {
publicPath: '/',
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
},
entry: {
main: './src/index.tsx',
'pdf.worker': path.join(__dirname, '../node_modules/pdfjs-dist/build/pdf.worker.js'),
},
module: {
rules: [
{
test: /\.(ts|js)x?$/i,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react',
'#babel/preset-typescript',
],
},
},
},
{
test: /\.(sa|sc|c)ss$/i,
use: [
'style-loader',
'css-loader',
'sass-loader',
{
loader: 'postcss-loader', // postcss loader needed for tailwindcss
options: {
postcssOptions: {
ident: 'postcss',
plugins: [tailwindcss, autoprefixer],
},
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: '../fonts',
},
},
{
test: /runtime-config.js$/,
use: [
{
loader: 'file-loader',
options: {
name: 'runtime-config.js',
},
},
],
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
}),
new NormalModuleReplacementPlugin(
/^pdfjs-dist$/,
(resource) => {
// eslint-disable-next-line no-param-reassign
resource.request = path.join(__dirname, '../node_modules/pdfjs-dist/webpack.js')
},
),
new CopyPlugin({
patterns: [
// relative path is from src
{ from: 'public/images', to: 'images' },
],
}),
// Add type checking on dev run
new ForkTsCheckerWebpackPlugin({
async: false,
}),
// Environment Variable for Build Number - Done in NPM scripts
new DefinePlugin({
VERSION_NUMBER: JSON.stringify(process.env.VERSION_NUMBER || 'development'),
}),
// Add lint checking on dev run
new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
}),
],
devtool: 'inline-source-map',
};
export default config

Cannot find module Error (React, TypeScript, Webpack)

Want to run app, but get the following error:
This is my project structure:
this is my app module
i use export and also export default are same:
app component
and the imports of the module:
My webpack :
const devSever = (isDev) => !isDev ? {} : {
devServer: {
open: true,
hot: true,
port: 7070,
contentBase: path.join(__dirname,'public')
}
};
const esLintPlugin = (isDev) => isDev ? [] : [new ESLintPlugin({ extensions: ['.ts', '.tsx ','.js']}) ]
module.exports = ({develop}) => ( {
mode: develop ? 'development': 'production',
devtool: develop ? 'inline-source-map' : false,
entry:{
app: './src/index.tsx',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
assetModuleFilename: 'assets/[hash][ext]' //may be hash
},
module: {
rules: [
{
test: /\.(ts|tsx|js)$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|svg)$/i,
type: 'asset/resource'
},
{
test: /\.(woff(2)?|eot|ttf|otf)$/i,
type: 'asset/resource'
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader,'css-loader']
}
]
},
resolve: {
extensions: ['.tsx','.ts','.js']
},
plugins: [
new CircularDependencyPlugin({
exclude: /a\.js|node_modules/,
include: /dir/,
failOnError: true,
allowAsyncCycles: false,
cwd: process.cwd()
}),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'style.css'
}),
new CopyPlugin({
patterns: [{from: './public' }]
}),
new CleanWebpackPlugin({cleanStaleWebpackAssets: false}),
...esLintPlugin(develop)
],
...devSever(develop)
});
it's all work good only if there are not imports and if i write code only in one component
you check out tsconfig.json
{
"include": ["src/**/*"],
"compilerOptions": {
"rootDir": "./src"
}
}

How to split chunks when authoring libraries with webpack 4?

I'm trying to publish a custom react component to a private repository.
I use react-loadable to load a subcomponent on demand. When running locally, everything works fine. The index.js file correctly makes a request to the chunk.js file when needed. However, when published and used from another project, the component hits a 404 error when trying to request the subcomponent chunk.
How am i supposed to split chunks and load them on demand when authoring a library? Is this even possible or am i thinking about it the wrong way?
Here's my webpack.config.js in case it's a simple matter of configuration:
module.exports = () => ({
context: __dirname,
mode: 'development',
entry: './src/index.jsx',
output: {
path: path.join(__dirname, './dist'),
filename: "index.js",
library: "reactcombobox",
libraryTarget: "umd",
publicPath: path.join(__dirname, './dist'),
umdNamedDefine: true
},
plugins: [
new webpack.LoaderOptionsPlugin({ options: { context: __dirname}}),
new CleanWebpackPlugin([path.join(__dirname, './dist')], {verbose: true, allowExternal: true})
],
module: {
rules: [
{
test: /.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
['#babel/preset-env', {
"targets": {
"browsers": ["last 4 Chrome versions"]
}
}],
'#babel/preset-react'
],
plugins: [
'#babel/plugin-transform-react-jsx',
'#babel/plugin-proposal-class-properties',
'#babel/plugin-syntax-dynamic-import'
]
}
}
},
{
test: /.css$/,
use: ["style-loader","css-loader"]
}
]
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react',
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom',
}
},
resolve: {
extensions: ['*', '.js', '.jsx']
}
});
if your component no relative please split to more file and use export {a1,a2};
do not use loadable.

Resources