I try to create react library with Webpack.
Simplified structure of library:
+ Base
|
|--- index.js
export * from "./Base";
|--- Base.jsx
export const Base = { "base_property_1": "base_property_1_value" };
+ Data
|
|--- index.js
export * from "./Data";
|--- Data.jsx
import { Base } from "../Base";
export const Data = { "data_property_1": "data_property_1_value", ...Base };
+ Red
|
|--- index.js
export * from "./Red";
|--- Red.jsx
import React from "react";
export const Red = () => <div>[Red]</div>;
I try to build library with this webpack.library_create.config.js:
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: {
"Base": path.resolve(__dirname, "./library_src/Base"),
"Data": path.resolve(__dirname, "./library_src/Data"),
"Red": path.resolve(__dirname, "./library_src/Red"),
},
externals: {
"react": "commonjs react",
"react-dom": "commonjs react-dom",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
optimization: {
minimize: false,
splitChunks: {
chunks: "all",
minChunks: 2,
minSize: 1,
},
},
output: {
clean: true,
filename: "[name]/index.js",
libraryTarget: "umd",
library: "Astra",
path: path.resolve(__dirname, "./node_modules/#a/library"),
umdNamedDefine: true,
},
resolve: {
extensions: ["*", ".js", ".jsx"],
},
target: "web",
};
Then I try to start project:
+ dist
|--- index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
</head>
<body>
<div></div>
<script src="./bundle.js"></script>
</body>
</html>
+ library_use
|--- index.jsx
import React from "react";
import ReactDOM from "react-dom";
import { Data } from "#a/library/Data";
import { Red } from "#a/library/Red";
console.log(Data);
const App = () => <div>App <Red /></div>;
ReactDOM.render( <App />, document.querySelectorAll( "body > div" )[ 0 ] );
using webpack.library_use.config.js:
const path = require("path");
const webpack = require("webpack");
module.exports = {
entry: path.resolve(__dirname, "./library_use/index.jsx"),
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
],
},
resolve: {
extensions: ["*", ".js", ".jsx"],
},
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js",
},
plugins: [ new webpack.HotModuleReplacementPlugin() ],
devServer: {
hot: true,
open: true,
port: 3020,
static: [
path.resolve(__dirname, "./dist"),
{
directory: path.resolve(__dirname, "./dist"),
serveIndex: true,
watch: true,
},
],
},
};
And I getting error: Uncaught TypeError: Cannot read properties of undefined (reading 'Data')
i.e. Data is not initialized.
If I remove dependency Base from Data, then Data initialized:
+ Data
|--- Data.js
// import { Base } from "../Base";
// export const Data = { "data_property_1": "data_property_1_value", ...Base };
export const Data = { "data_property_1": "data_property_1_value", };
How to set up webpack.library_create.config.js to build my library with dependencies to work my project (with webpack.library_use.config.js)?
This project on git https://github.com/rosinfotech/issue_210921_webpack_library_dependencies
Eventually, nobody answered my issue. Even collaborators of the Webpack projects define the issue as discussion and suppose to figure out in Webpack code to resolve this problem myself https://github.com/webpack/webpack/discussions/14303#discussioncomment-1376696 But I chosen another way – the Rollup, which resolved my task very effectively https://github.com/rosinfotech/issue_210921_webpack_library_dependencies/tree/rollup
Related
I'm creating a Todo app and I am using webpack to bundle multiple js files. I'm having trouble importing my functions and classes between the different js files. I keep receiving the error "SyntaxError: cannot use import statement outside a module.". I have set the entry in the webpack.config.js file to the index.js file. I can import from all the other js files into the index.js file and it works. Where I am having trouble is importing between all the js files themselves. I am fairly new to webpack and any help would be greatly appreciated. Thanks!
This is the task.js file code that I am trying to import into the ui.js file.
import { v4 as uuidv4 } from 'uuid';
export class Task {
constructor(title, description, dueDate) {
return Object.assign(this, { id: uuidv4(), title, description, dueDate, completed: false })
}
}
Here is the code in the ui.js file
import { Task } from './task.js';
const taskOne = new Task('Hello', "goodbye")
console.log(taskOne);
Here is the webpack.config.js file
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
assetModuleFilename: '[name][ext]'
},
devtool: 'source-map',
devServer: {
static: {
directory: path.resolve(__dirname, 'dist')
},
port: 3000,
open: true,
hot: true,
compress: true,
historyApiFallback: true
},
module: {
rules: [
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.(png|jpg|jpeg|svg|gif)$/i,
type: 'asset/resource'
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Todo App',
filename: 'index.html',
template: './src/template.html'
})
]
}
I'm trying to setup vue app using webpack.
This is my webpack.config.js file:
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
"Shared/global": './ClientApp/src/js/Shared/global.js',
},
output: {
filename: 'js/[name].entry.js',
path: path.resolve(__dirname, 'dist'),
publicPath: ""
},
devtool: 'source-map',
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader'],
},
{
test: /\.(eot|woff(2)?|ttf|otf|svg)$/i,
type: 'asset'
},
{
test: /\.js$/,
use: {
loader: "babel-loader",
},
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css"
})
]
};
And this is the entry file:
import {createApp} from 'vue';
import { createStore } from 'vuex'
const _ = require('lodash')
In my layout.html I call global.entry.js as such:
<body>
<div id="layoutApp">
<h1>HELLO</h1>
</div>
</body>
<script type="module" src="/dist/js/Shared/global.entry.js" defer></script>
<script src="/ClientApp/src/js/Shared/layout.js" defer></script>
Then I try to use vue in layout.js:
const layoutApp = createApp({
mounted(){
console.log("layout is mounted VUE")
},
});
layoutApp.mount("#layoutApp")
var array = [1];
var other = _.concat(array, 2, [3], [[4]]);
console.log(other);
But in chrome console it said createApp is not defined. But if I run only lodash code, lodash works fine. I cant figure out what I did wrong. Any help would be very helpful
I have created module A which is a component library for my React App. Which I plan on using on module B which is my actual React App.
I have an index.js whereby I export my components from module A by using loadable components in the following fashion
import loadable from '#loadable/component'
export const Theme = loadable(() => import('./Theme'))
export const OtherComponent = loadable(() => import('./OtherComponent'))
export const OtherComponent2 = loadable(() => import('./OtherComponent2'))
I therefore build and deploy module A to npm by using the following webpack configuration
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const TerserPlugin = require("terser-webpack-plugin")
const LoadablePlugin = require('#loadable/webpack-plugin')
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
minimize: true,
concatenateModules: false,
minimizer: [new TerserPlugin({
terserOptions: {
keep_fnames: true
}
})],
},
entry: {
main: './src/components/index.js',
},
output: {
publicPath: '/',
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
library: "myComponentLibrary",
libraryTarget: "umd",
globalObject: "this"
},
externals: {
react: {
root: 'React',
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
},
},
plugins: [new CleanWebpackPlugin(), new LoadablePlugin()],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {
cacheDirectory: true
}
}
],
},
{
test: /\.(jpe?g|png|gif|svg)$/,
type: 'asset/inline'
},
]
}
}
I expected that when I npm install module A on module B to be able to import and render my components but instead I get the following error.
loadable-components: failed to asynchronously load component { fileName: undefined, chunkName: undefined, error: 'Loading chunk 2661 failed.\n(error: 2661.js)' }
Please provide some guidance on how I can solve this issue
If everything is working well on development but for production is not and you face with this error, Add this <base href="/"/> to head of index.html:
<!DOCTYPE html>
<html>
<head>
<base href="/"/>
<meta charset="utf-8" />
<title>Foo project</title>
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Now, I think everything is working well.
This problem is because of html5 routing, you can search about it.
bundle.js page not found error, and i add the script tag to the index.html file.
In the webpack.config.js file, set the output path as
output: {
path: path.resolve(__dirname, "dist"),
filename: 'bundle.js',
},
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
AppContainer.jsx
'use strict';
import React, {Component} from 'react';
export default class AppContainer extends Component {
constructor(props) {
super(props);
}
render() {
return <div>
<h2>Hello World</h2>
</div>;
}
}
webpack.config.js
'use strict';
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, "app.jsx"),
output: {
path: path.resolve(__dirname, "dist"),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: "babel-loader",
options: {
presets: ["env", "react"]
}
}
}
]
},
resolve: {
extensions: [".js", ".jsx"]
},
devServer: {
contentBase: path.join(__dirname, "/"),
compress: true
},
devtool: "source-map"
};
App.jsx
'use strict';
import React from 'react';
import AppContainer from './AppContainer.jsx';
render(<AppContainer/>, document.getElementById('app'));
this is the my react repository link : react link description here
Not a direct answer to your question but maybe you can give a shot to HtmlWebpackPlugin? It will automatically generate HTML for you and properly link your bundle in a script.
run npm i --save-dev html-webpack-plugin, and set:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path');
module.exports = {
entry: path.resolve(__dirname, "app.jsx"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
publicPath: '/' // not sure if that will make any difference though
},
plugins: [
new HtmlWebpackPlugin()
],
module: {
rules: [
{
test: /\.jsx?$/,
use: {
loader: "babel-loader",
options: {
presets: ["env", "react"]
}
}
}
]
},
resolve: {
extensions: [".js", ".jsx"]
},
devServer: {
contentBase: path.join(__dirname, "/"),
compress: true
},
devtool: "source-map"
};
I'm newbie in webpack and react. hope you can help me.
I faced a problem and can't find any working solution in the internet.
When i trying to run webpack-dev-serverI geting "Module not found: Error: Cannot resolve module 'components/app'" error all the time.
Here my files structure.
root/ webpack.config.js
var webpack = require('webpack');
var path = require('path');
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://127.0.0.1:8080/',
'webpack/hot/only-dev-server',
'./src'
],
output: {
path: path.join(__dirname, 'public'),
filename: 'bundle.js'
},
resolve: {
moduleDirectories: ['node_modules', 'src'],
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
};
root/ .babelrc
{
presets: ["react", "es2015"],
plugins: ["react-hot-loader/babel"]
}
root/src/index.js
import React from 'react';
import { render } from 'react-dom';
import App from 'components/app';
render(<App />, document.getElementById('app'));
root/src/components/app.js
import React from 'react';
export default class App extends React.component {
render() {
return (
<div>
<h1>Hello There</h1>
</div>
);
}
}
I agree with Robert Moskal answer, use Relative path to import, at the same time if you really want the absolute path to work you may have to add one more line in your webpack.config.js inside your resolve section of it add this below line
root: path.resolve('./src'),
this will help to resolve the root and you can easily import using absolute path from folders inside the src folder. I would show you my sample webpack.config.js below
'use strict';
const path = require('path');
const loaders = require('./webpack/loaders');
const plugins = require('./webpack/plugins');
const applicationEntries = process.env.NODE_ENV === 'development'
? ['webpack-hot-middleware/client?reload=true']
: [];
const mainEntry = process.env.NODE_ENV === 'development'
? './src/sample/index.tsx'
: './src/lib/index.tsx';
module.exports = {
entry: [mainEntry].concat(applicationEntries),
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js',
publicPath: '/',
sourceMapFilename: '[name].js.map',
chunkFilename: '[id].chunk.js',
},
devtool: process.env.NODE_ENV === 'production' ?
'source-map' :
'inline-source-map',
resolve: {
root: path.resolve('./src'),
extensions: [
'',
'.webpack.js',
'.web.js',
'.tsx',
'.ts',
'.js',
'.json',
],
},
plugins: plugins,
devServer: {
historyApiFallback: { index: '/' },
},
module: {
preLoaders: [
loaders.tslint,
],
loaders: [
loaders.tsx,
loaders.html,
loaders.css,
loaders.scss,
loaders.eot,
loaders.svg,
loaders.ttf,
loaders.woff,
loaders.json,
{
test: /\.png$/,
loader: 'url-loader',
query: { mimetype: 'image/png' },
},
],
},
externals: {
'react/lib/ReactContext': 'window',
'react/lib/ExecutionEnvironment': true,
'react/addons': true,
},
};
You need to specify a relative path to app in your index.js file. So
import App from './components/app'
Without the relative path notation, the module import system looks in the node_modules directory.
You're looking for module aliasing. The resolve section of your config should look something like:
const path = require('path');
resolve: {
modules: [path.resolve(__dirname, 'src'), 'node_modules'],
extensions: ['', '.js'],
alias: {
components: path.resolve(__dirname, 'src/components/')
}
}
This is equivalent to the paths option in TypeScript config files.