How to correctly expose jQuery with Webpack 5? - javascript

Is there any specific way to expose jQuery with Webpack 5?
It used to work on Webpack 4 OK, with the config bellow, but it shows the Uncaught Reference Error: jQuery is not defined error now with 5.
module: {
rules: [
{
test: require.resolve('jquery'),
loader: 'expose-loader',
options: {
exposes: ['$', 'jQuery'],
},
},

Confirming #Sam Chen 's comment above, Webpack 5 (as of 5.75) does not require expose-loader to make $ available as an import. It was simplest to uninstall the loader, remove it from webpack.config.js, and add
import $ from 'jquery';
to all files that used it. This can get messy in the case of TypeScript projects with #types/jquery, as pages where the import is missing may not warn about it.

Related

Module not found: Error: You attempted to import babel-preset which falls outside of the project src/ directory

I'm developing an application created using create-react-app
But then I needed to use mediainfojs library, this library requires wasm files, and based on what I understood I couldn't add it using create-react-app, I had to eject it.
After ejecting it, I went to mediainfo information on how to add the wasm on the webpack
They use the CopyPlugin, but then when I tried to do that it complained about the versions of my webpack (4) and the CopyPlugin.... so, I decided to migrate to webpack 5
That is when the pain starts... after follow their migration tutorial and do a bunch of modifications on my webpack.config I got to the following error while runing yarn build:
Module not found: Error: You attempted to import /MyWorkspace/project/node_modules/babel-preset-react-app/node_modules/#babel/runtime/helpers/esm/asyncToGenerator which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
The only place calling this babel-preset-react-app are in the configuation
Here:
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve("babel-loader"),
options: {
customize: require.resolve(
"babel-preset-react-app/webpack-overrides"
),
And here:
{
test: /\.(js|mjs)$/,
exclude: /#babel(?:\/|\\{1,2})runtime/,
loader: require.resolve("babel-loader"),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve("babel-preset-react-app/dependencies"),
{ helpers: true },
],
],
cacheDirectory: true,
cacheCompression: isEnvProduction,
// If an error happens in a package, it's possible to be
// because it was compiled. Thus, we don't want the browser
// debugger to show the original code. Instead, the code
// being evaluated would be much more helpful.
sourceMaps: false,
},
},
I have looked into similar issues reported here, but mostly of them seem to be related to either static files being dynamically imported or imports referencing ".." dir after the project directory
The full webpack config file is here
I'm probably missing something very silly, I'd be glad if someone can point it out.
I had a similar challenge and I was able to fix this by adding these definitions at the top of my webpack.config file
const babelRuntimeEntry = require.resolve('babel-preset-react-app');
const babelRuntimeEntryHelpers = require.resolve(
'#babel/runtime/helpers/esm/assertThisInitialized',
{ paths: [babelRuntimeEntry] }
);
const babelRuntimeRegenerator = require.resolve('#babel/runtime/regenerator', {
paths: [babelRuntimeEntry]
});
Then where you have the ModuleScopePlugin in the resolve.plugins
update it to be
new ModuleScopePlugin(paths.appSrc, [
paths.appPackageJson,
babelRuntimeEntry,
babelRuntimeEntryHelpers,
babelRuntimeRegenerator])
I'm also attempting to upgrade an ejected CRA project to Webpack 5. I was able to move forward using babel-preset-react-app-webpack-5, only to encounter the next CRA-related issue.
Be sure to replace calls like require.resolve("babel-preset-react-app/dependencies") with require.resolve("babel-preset-react-app-webpack-5/dependencies").
Also, be aware the package does not appear to be production-ready, but my own project is still in early development.
I had this issue with a few other babel packages after trying to upgrade an ejected CRA app to webpack v5. I tried many different approaches some of which worked in dev but not in prod and vice versa. I found this comment in the storybook github and it was the only thing that that seemed to work in all scenarios for me.
It's kinda annoying, but by simply moving the offending packages from devDependencies in my package.json to dependencies, it seems to fix the issue. I could spend more time trying to figure out why that fixes it, but I'll leave that to someone with more free time. :)

Why webpack doesn't tree-shake the lodash when using "import * as _"?

I am learning about tree-shaking with a webpack 4/React application that uses Lodash.
At first, my Lodash usage looked like this:
import * as _ from "lodash";
_.random(...
I soon learned, via the BundleAnalyzerPlugin, that the entirety of Lodash was being included in both dev and prod builds (527MB).
After googling around I realized that I needed to use a specific syntax:
import random from "lodash/random";
random(...
Now, only random and it's dependencies are correctly included in the bundle, but I'm still a little confused.
If I need to explicitly specify functions in my import statement, then what role is the tree-shaking actually playing?
The BundleAnalyzerPlugin isn't showing a difference in payload size when comparing between dev and production mode builds (it's the correct small size in both, but I thought that tree-shaking only took place with production builds?).
I was under the impression that TreeShaking would perform some sort of static code analysis to determine which parts of the code were actually being used (perhaps based on function?) and clip off the unused bits.
Why can't we always just use * in our import and rely on TreeShaking to figure out what to actually include in the bundle?
In case it helps, here is my webpack.config.js:
const path = require("path");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
module.exports = {
entry: {
app: ["babel-polyfill", "./src/index.js"]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false
})
],
devtool: "source-map",
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist"),
chunkFilename: "[name].bundle.js",
publicPath: ""
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
include: /src/,
options: {
babelrc: false,
presets: [
[
"env",
{
targets: {
browsers: ["last 2 Chrome versions"]
}
}
],
"#babel/preset-env",
"#babel/preset-react"
],
plugins: ["syntax-dynamic-import"]
}
},
{
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve("ts-loader"),
options: {
compiler: require.resolve("typescript")
}
}
]
}
]
},
resolve: {
symlinks: false,
extensions: [".js", ".ts", ".tsx"],
alias: {
react: path.resolve("./node_modules/react")
}
}
};
I'm invoking webpack with webpack --mode=development and webpack --mode=production.
All two existing answers are wrong, webpack do treeshake import *, however that only happens when you're using a esmodule, while lodash is not. The correct solution is to use lodash-es
Edit: this answer only applies to webpack4, while webpack 5 supported a limited subset of tree shaking for commonjs, but I haven't tested it myself
Actually, it is not related to the Webpack ability to tree-shake. base on Webpack docs about tree-shaking
The new webpack 4 release expands on this capability with a way to provide hints to the compiler via the "sideEffects" package.json property to denote which files in your project are "pure" and therefore safe to prune if unused
When you set the "sideEffects: false on your package.json based on the linked docs:
All the code noted above does not contain side effects, so we can simply mark the property as false to inform webpack that it can safely prune unused exports.
If you have some files or packages which you know they are pure add them to sideEffects to prune it if unused. There are some other solutions to do tree-shaking that I proffer to read the whole article on Webpack docs.
One of the manual ways are using direct importing like below:
import get from 'lodash/get';
That Webpack understands add just get from the whole lodash package. another way is destructing importing that needs some Webpack optimization for to tree-shaking, so you should import like below:
import { get } from 'lodash';
Also, another tricky way is just to install a specific package, I mean:
yarn add lodash.get
OR
npm install --save lodash.get
Then for import just write:
import get from 'lodash.get';
Definitely, it is not tree-shaking, it is a tight mindset development, but it causes you just add what you want.
BUT
YOU DON'T DO ANYTHING OF ABOVE SOLUTIONS, you just add the whole package by writing import * as _ from "lodash"; and then use _.random or any function and expect Webpack understand you wanna the tree-shaking be happening?
Surely, the Webpack works well. you should use some configs and coding style to see the tree-shaking happens.
If you're already using Babel, the easiest method to properly tree shake lodash is to use the official babel-plugin-lodash by the lodash team.
This uses Babel to rewrite your lodash imports into a more tree-shakeable form. Doing this dropped my team's bundle size by ~32kB (compressed) with less than 5 minutes of effort.

How to use webpack with download jquery?

Downloaded the minified versions of jQuery and jQuery_cookie. Trying to use webpack on them, but getting an error:
ERROR in ./src/js/jquery_cookie.js
Module not found: Error: Can't resolve 'jquery' in 'C:\Users\MSI-PC\Documents\code_site\server2\src\js'
# ./src/js/jquery_cookie.js 11:2-29
# ./src/js/index.js
index.js :
require('./jquery-3.2.1.min.js');
require('./jquery_cookie.js');
Site:
node_modules/
dist/
public/
src/
css/
ejs/
js/
index.js
jquery-3.2.1.min.js
jquery_cookie.js
server.js
package.js
webpack.config.js
webpack.config.js
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
devtool: 'source-map',
output: {publicPath: '/dist/'},
module: {
rules: [{test: /\.ejs$/,
use: ['ejs-loader']}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/ejs/index.ejs',
minify: {collapseWhitespace: true}
})
]
}
Already tested with ìmport jquery from './jquery-3.2.1.min.js' but it didn't work.
Also tested to insert into jquery_cookie in to the root of jQuery, but that didn't work too.
The last thing tried was to add this window.$ = window.jQuery = require("jquery"); into my index.js, but that also failed.
Edit
Edit to add news informations. Tested to install jquery npm install jquery and to require him into my index.js. Getting no error when I started webpack. But my other API like semantic-ui, jQuery-ui and others files .js that use jQuery didn't work. My console return error :
ReferenceError: jQuery is not defined jquery-ui-1.12.1.min.js:14:3
ReferenceError: jQuery is not defined semantic.min.js:11:1
ReferenceError: $ is not defined client.js:96
Also tested with insert into webpack.config.js a loader expose-loader but also failed :
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
with plugin :
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})
You don't need webpack to make use of jquery. Just use a script tag and point to your library.
The best place to insert it is before the end of your body tag.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Tutorial: https://www.w3schools.com/jquery/jquery_get_started.asp
Read more: https://jquery.com/download/
I believe the problem is here: https://github.com/carhartl/jquery-cookie/blob/master/src/jquery.cookie.js#L14
jquery_cookie is trying to require('jquery'), but you don't have one in node_modules. You should install it:
npm i jquery
This error should no longer appear.
P.S. There can probably be a solution using webpack's resolve.alias or something similar in order to use your file while requesting require('jquery'), but I don't see a reason for not doing regular npm install in favor of a locally downloaded jquery file. Not worth the hassle.

Emoji dictionary cant find modules ./emojis

I'm currently trying to use emoji-dictionary on my project but it fails to run!
I'm receive the index.js:2 Uncaught Error: Cannot find module "./emojis" error!
Since the reactjs tag appears, I speculate you use Webpack and you didn't set up the json-loader. emojis.json is a file from the emojilib package which is a dependency of emoji-dictionary.
Install json-loader:
npm install --save-dev json-loader
And then configure it:
module.exports = {
module: {
rules: [
{
test: /\.json$/,
use: 'json-loader'
}
]
}
}
Check out json-loader on GitHub for more information.
If this is not solving the issue, you may need to explain a little bit the context. It seems to not be related to the package itself because •it's working on my machine•. 😅

Webpack build fails with es6 react.js

I use React.js, Webpack, ...props syntax, arrow functions.
When I run "npm run build", I get this error:
ERROR in bundle.js from UglifyJs
SyntaxError: Unexpected token punc «(», expected punc «:» [bundle.js:77854,15]
Here is my debug.log
My webpack.config
How to run build successfully?
I found the line which causes the bug, here it is:
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
I don't know why. :(
Without it, all my ES6 syntax works and compiled without any errors.
Any Help please
This error happens if you use have an npm dependency that has ES6 syntax. It happended to me, too, with Preact (see https://github.com/developit/preact-compat/issues/155).
You can fix it by adding the dependency explicitly to the modules that are loaded through babel, like so:
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
srcPath,
// we need to include preact-compat
// otherwise uglify will fail
// #see https://github.com/developit/preact-compat/issues/155
path.resolve(__dirname, '../../../node_modules/preact-compat/src')
]
}
]
}
In bundle.js, line 77854, character 15, there is a parenthese after a object properties name, instead of a :.
There must be something like :
{property () {}}
instead of
{property : function () {}}
Edit (thanks to #handoncloud): The first is valid ES6, and is a shorthand for the second, that is the equivalent in ES5.
The problem is, that the build does not fully support ES6.
Found it.
React-Bootstrap-Table have a dependency named React-Modal.
I installed React Modal by npm install react-modal without --save or --save-dev. So React-Modal wasn't not listed in my package.json.
Now everything is ok.
SOLUTION : npm install react-modal --save

Categories