I'm working on React project and I had found out that one of budles files is too big and I need to split it. So, I tried to use import() sintax:
import React from 'react';
import thumbnails from './thumbnails.json';
export default class Portfolio extends React.Component {
constructor(props) {
super(props);
import('react-image-gallery').then(module => {
const ImageGallery = module.default;
this.galleries = thumbnails.map((thumbnail, i) => {
let items = [];
for (let i = 0; i < thumbnail.gallery.amount; i++) {
items.push({
original: `${thumbnail.gallery.href}/${i}.png`,
thumbnail: `${thumbnail.gallery.href}/${i}m.png`,
})
}
return (
<div className="gallery">
<ImageGallery key={i} items={items} thumbnailPosition="left" showPlayButton={false}
onImageLoad={this.onGalleryLoad.bind(this, thumbnail.gallery.amount)}/>
<button className="gallery__close" onClick={this.onCloseClick.bind(this)}>×</button>
</div>
)
});
});
}
Portfolio is the main component for one page. Later, when I open the page, there's an error Uncaught (in promise) ChunkLoadError: Loading chunk 0 failed.
As I saw, JavaScript tries to load file 0.bundle.js from the portfolio directory. While needed chunk is 0.chunk.js that is located in the root directory.
Here's my Wepback config:
const TerserPlugin = require('terser-webpack-plugin');
module.exports = env => {
const isDev = env.MODE === 'development';
return {
mode: isDev ? 'development' : 'production',
devtool: 'source-map',
entry: {
'./home/script': './home/script.jsx',
'./portfolio/script': './portfolio/script.jsx',
'./prices/script': './prices/script.jsx',
'./contacts/script': './contacts/script.jsx',
'./extra/script': './extra/script.jsx',
'./extra/locations/script': './extra/locations/script.jsx',
'./extra/poses/script': './extra/poses/script.jsx',
'./extra/stylists/script': './extra/stylists/script.jsx',
'./extra/studios/script': './extra/studios/script.jsx',
},
output: {
path: __dirname,
publicPath: __dirname,
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js',
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ['#babel/preset-env', '#babel/react'],
plugins: [
'#babel/plugin-proposal-class-properties',
'#babel/plugin-transform-runtime',
'#babel/plugin-syntax-dynamic-import',
]
}
}
},
],
},
optimization: {
minimize: !isDev,
minimizer: [new TerserPlugin({
test: /.js$/i,
extractComments: false,
terserOptions: {
output: {
comments: false,
},
},
})],
},
resolve: {
extensions: ['.jsx', '.js'],
}
}
};
Try changing your output object to
output: {
......
chunkFilename: '[name].[chunkhash].js',
}
Check this out for reference https://github.com/webpack/webpack/issues/9207#issuecomment-499448929
I've found the answer. To escape searching in subrirectories, you should use publicPath: '/' in the output option of webpack. It was sugested to use chunk hashes, but as I tried it, it's not really nesessary. The whole solution is here:
output: {
path: __dirname,
publicPath: '/',
filename: '[name].bundle.js',
chunkFilename: './assets/chunks/[name].chunk.js',
}
The ./assets/chunks/ part is not required. It's just for holding all chunks in one directory
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 am doing some upgrades to node a package which uses webpack. The package used to use webpack 5.9 for generating a small bundle, then using eval() was extracting some js code.
This is the webpack conf:
function getBaseWebpackConfig() {
return {
context: path.resolve(__dirname, '../'),
mode: 'development',
entry: "./test/input/icon.js",
devtool: false,
output: {
path: outputDir,
filename: bundleFileName,
publicPath: '',
library: {
type: 'commonjs2',
}
},
module: {
rules: [
{
test: /\.svg/,
exclude: /node_modules/,
loader: svg-loader,
options: {}
}
]
}
}
}
Now, moving to 5.73.0, this behaviour has changed; tests stopped running. After doing some debug, I have found the following.
With webpack < 5.21.2 the bundle starts as:
module.exports =
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
With webpack > 5.22.0 the bundle starts as:
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
Essentially, it does not have a top module.exports anymore and this breaks the rest of the code.
I could not find any reason this. The changelog does not give me any clue. Might it be a bug?
I'm not a webpack expert. But, comparing yours with my webpack configs I created recently (using the latest webpack for a PWA app). My settings are inside a module.exports. Maybe that's why module.exports is not in your bundle. e.g.
module.exports = {
context: path.resolve(__dirname, '../'),
mode: 'development',
entry: "./test/input/icon.js",
devtool: false,
output: {
path: outputDir,
filename: bundleFileName,
publicPath: '',
library: {
type: 'commonjs2',
}
},
module: {
rules: [
{
test: /\.svg/,
exclude: /node_modules/,
loader: svg-loader,
options: {}
}
]
}
}
}
Plus I've got three webpack config files common,dev and prod and use merge to combine them.
e.g. my webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const path = require('path');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
output: {
filename: "[name].bundle.js",
},
module: {
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css"
}),
new ForkTsCheckerNotifierWebpackPlugin(),
]
});
So basically the problem is described in a title. I'm trying to use a library(quill) that runs only in browser environment and in my project I have two webpack configs, one for a client build and second for a server. After adding this library server build is failing because of this line. So the problem here is my webpack doesn't look at node_modules folder and not converting this line for babel. So I used webpackNodeExternals and added this file in whitelist. After that my build failing because quill uses document somewhere in its code, and of course document is not defined in node env. So far I tried ProvidePlugin and defined document from jsdom, but then somewhere in quill code base they are using this.textNode = document.createTextNode(Cursor.CONTENTS); and my build is failing again. probably because document from jsdom is not the same as browser's window.document...
The solution I'm looking for is how to tell my server not to build this library and its dependecies at all, or somehow replace it with something else only in server build. I don't need this on server side at all, only in client build which is passing correctly
EDIT: Added webpack.config.js that used for server build
const path = require('path')
const webpack = require('webpack')
const dotenv = require('dotenv')
const webpackNodeExternals = require('webpack-node-externals')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')
const StartServerPlugin = require('start-server-webpack-plugin')
const CaseSensetivePathsWebpackPlugin = require('case-sensitive-paths-webpack-plugin')
const dotenvPath = process.env.DOTENV_PATH
? path.resolve(process.cwd(), process.env.DOTENV_PATH)
: path.resolve(process.cwd(), '.env')
const { parsed: envs = {} } = dotenv.config({ path: dotenvPath })
console.info(
`Environment was read from '${path.relative(process.cwd(), dotenvPath)}'`
)
const OUTPUT_PATH = path.resolve(__dirname, './build')
module.exports = {
name: 'webClient/server',
bail: process.env.NODE_ENV === 'production',
mode: process.env.NODE_ENV,
entry: [
'#babel/polyfill',
process.env.NODE_ENV === 'development' && 'webpack/hot/poll?666',
'./server'
].filter(Boolean),
output: {
path: OUTPUT_PATH,
filename: 'server.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|scripts)/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: process.env.NODE_ENV === 'development'
}
},
{
loader: 'eslint-loader',
options: {
cache: process.env.NODE_ENV === 'development',
rules: {
'prettier/prettier': 'off'
}
}
}
]
},
{
test: /\.css$/,
exclude: /(node_modules|scripts)/,
use: [
{
loader: 'css-loader',
options: {
url: false,
import: false,
modules: true,
localIdentName: '[local]___[hash:base64:5]',
exportOnlyLocals: true,
importLoaders: 1
}
},
'postcss-loader'
]
}
]
},
devtool: 'source-map',
watch:
process.env.NODE_ENV === 'development',
stats: {
chunks: false,
colors: true
},
target: 'node',
externals: [
webpackNodeExternals({
whitelist: ['webpack/hot/poll?666']
})
],
optimization: {
minimizer: [
process.env.NODE_ENV === 'production' &&
new TerserWebpackPlugin({
parallel: true,
sourceMap: true
})
].filter(Boolean)
},
plugins: [
new CleanWebpackPlugin([OUTPUT_PATH]),
process.env.NODE_ENV === 'development' &&
new webpack.HotModuleReplacementPlugin(),
process.env.NODE_ENV === 'development' &&
Boolean(process.env.SERVER_WATCH) &&
new StartServerPlugin({
name: 'server.js',
nodeArgs: ['--inspect']
}),
new CaseSensetivePathsWebpackPlugin(),
new webpack.DefinePlugin({
'process.env': Object.assign(
{
SERVER: true
},
Object.keys(envs).reduce(
(destination, key) =>
Object.assign(destination, {
[key]: JSON.stringify(envs[key])
}),
{}
)
)
})
].filter(Boolean),
resolve: {
modules: ['node_modules', 'src'],
extensions: ['.js', '.jsx', '.json', '.css']
}
}
I am using Vue with Webpack, but I when I import or require another file to be included into my main document, the file seems to have loaded, as in it doesn't give me any errors, but the imports within the files do not load, and I can't use any variables from the files. For example, I have this main document:
import './bootstrap';
import VueRouter from 'vue-router';
Vue.use(VueRouter);
let Default = Vue.component('Default', {
template: `
<li>
This is home
</li>
`
});
let About = Vue.component('About', {
template: `
<li>
This is about us maaan
</li>
`
});
var router = new VueRouter({
routes: [
{ path: '/', component: Default },
{ path: '/about', component: About }
]
})
require('./sass/styles.scss');
new Vue({
el: '#app',
router: router
})
...and my bootstrap file is simply:
import Vue from 'vue';
import axios from 'axios';
I get the following error: Uncaught ReferenceError: Vue is not defined, as if the file had not been included. If I make any changes to the path, I get a file not found error, so I imagine that the file is located. the same for any variables in the file, they are not available in the main file afterwards. This is my webpack.config.js:
var path = require('path')
var webpack = require('webpack')
var inProduction = (process.env.NODE_ENV === 'production');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: 'dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: 'images/[name].[ext]?[hash]'
}
},
{
test: /\.s[ac]ss$/,
use: ExtractTextPlugin.extract({
use: ['css-loader', 'sass-loader'],
fallback: 'style-loader'
})
}
]
},
plugins: [
new ExtractTextPlugin({
filename: 'styles.css',
disable: process.env.NODE_ENV === "development"
})
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
// new webpack.optimize.UglifyJsPlugin({
// sourceMap: true,
// compress: {
// warnings: false
// }
// }),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
Many thanks!
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.