Bundle sha3/binary modules with Webpack - node.js

Webpack warns when I bundle my source as it can't resolve the 'sha3' module.
$ npm run build
WARNING in ./~/keccakjs/index.js
Module not found: Error: Can't resolve 'sha3' in '<PROJ>\node_modules\keccakjs'
# ./~/keccakjs/index.js 2:19-34
# ./~/<lib>/index.js
# ./lib/<file>.js
Reason being the sha3 library has no js files.
Creating library <proj>\node_modules\sha3\build\Release\sha3.lib and object <proj>\node_modules\sha3\build\Release\sha3.exp
I am able to run require('sha3') in my project, however webpack cannot resolve it.
I looked at the docs here, regarding how webpack resolves libs.
Could someone point me to how I can include sha3 in/with my bundle.
My Webpack config:
module.exports = {
target: 'node',
entry: "./<lib>.js",
devtool: "source-map",
node: {
__dirname: false,
__filename: false,
},
output: {
path: "./dist",
filename: "<lib>.min.js"
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
]
}

What actually ended up working for me was:
resolve: {
alias: {
sha3: path.join(__dirname,'node_modules/sha3/build/Release/sha3.node')
},
},
module: {
rules: [
{test: /\.node$/, use: 'node-loader'},
]
},
That way I told it which file to import, when it wasn't able to resolve sha3. And the node-loader packages in the .node file!

Try using the binary loader from webpack from here. Then you can:
1) Define loaders in your WebPack config:
module.exports = {
target: 'node',
entry: "./<lib>.js",
devtool: "source-map",
node: {
__dirname: false,
__filename: false,
},
output: {
path: "./dist",
filename: "<lib>.min.js"
},
plugins: [
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
})
],
module: {
loaders: [
{ test: /sha3$/, loader: 'binary' }
]
}
}
2) Use the loader directly in your import:
require('binary!sha3');

Related

How to transpile npm module with "optional chaining" code to earlier version of node?

Currently I am running node v16.13.1 and I wrote small npm package I would like to publish to npm and then install globally and run as executable.
Application works fine when built with current version but because I am using "optional chaining" (object?.something) it does not work with node 12.
I do not want to change code, but I would like to transpile it so it runs it in all node versions between 12 and 16+.
My webpack look like this:
const path = require("path");
const webpack = require("webpack");
module.exports = (env, argv) => {
console.log('Log::', env, argv);
const config = {
entry: './src/index.js',
devtool: (argv.mode === 'development') ? 'cheap-module-source-map' : undefined,
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js',
},
experiments: {
outputModule: true,
},
plugins: [
//empty pluggins array
new webpack.BannerPlugin({ banner: "#!/usr/bin/env node", raw: true }),
],
module: {
// https://webpack.js.org/loaders/babel-loader/#root
rules: [
{
test: /.m?js$/,
loader: 'babel-loader',
exclude: /node_modules/,
}
],
},
resolve: {
fallback: {
"fs": false,
"path": false,
"os": false,
assert: require.resolve('assert'),
path: require.resolve('path-browserify'),
util: require.resolve('util'),
},
},
target: "node12.22"
};
console.log('Log::', config);
return config;
}
and this is .babelrc
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"esmodules": true
}
}
]
]
}
running npm build with target: "node" gives following error:
Error: For the selected environment is no default ESM chunk format available:
ESM exports can be chosen when 'import()' is available.
running it with target: "node12.22" does not give any errors but when I try to run I get:
SyntaxError: Cannot use import statement outside a module
←[90m at Object.compileFunction (node:vm:352:18)←[39m
If I remove target:"node" all together I am getting following error when run:
TypeError: s.existsSync is not a function
If I run it without fallback: { "fs": false then I get compile errors:
Module not found: Error: Can't resolve 'fs' in
Try adding the following to your Webpack config to have the optimizer output code that's compatible with ECMA 6, which does not include optional chaining:
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
ecma: 6,
mangle: false,
// compress: false, // NOTE: Not certain you can just pass false here, but I think probably
},
}),
],
},
And be sure to install the TerserJS Plugin and require it in your config, const TerserPlugin = require('terser-webpack-plugin');

Webpack 5 webpackMissingModule error for node_modules package

I've been working on upgrading a repository from Webpack version 4 to 5, and I've encountered a very strange problem where Webpack will throw an error at runtime telling me that a package in node_modules could not include a specific "module" (referring to a subdirectory of that package). The module in question is #hapi/joi, and the error I'm receiving is:
Error: Cannot find module './types/alternatives'
At one point it was telling me that the error related to that package, but now it just throws the error with no package context. I've dug into the #hapi/joi package, and I can see this set of imports in the index.js:
const internals = {
alternatives: require('./types/alternatives'),
array: require('./types/array'),
boolean: require('./types/boolean'),
binary: require('./types/binary'),
date: require('./types/date'),
func: require('./types/func'),
number: require('./types/number'),
object: require('./types/object'),
string: require('./types/string'),
symbol: require('./types/symbol')
};
I've verified that the ./types/alternatives directory exists and that it has an index.js of its own. This package also works fine on Webpack 4. I tried upgrading to the standalone joi package, and it threw the same error.
I'm pretty confused at to why this error is throw at runtime. I would think this would be a build error, though maybe it has something to do with building the target for node?
This is my Webpack config. It's mostly unmodified from v4:
{
entry: {
adviceServer: "./src/server/index.ts",
},
target: "node",
bail: true,
mode: env.NODE_ENV,
output: {
path: path.resolve(root, "dist", "js"),
filename: `[name].${env.ASSET_HASH}.js`
},
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: "ts-loader",
options: {
context: path.resolve(root, "src"),
configFile: tsconfigPath,
transpileOnly: false
}
}
],
exclude: [
"/node_modules",
"/**/*.test.ts/"
]
},
{
test: /\.s?css$/,
use: ["isomorphic-style-loader", "css-loader", "sass-loader"]
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js", ".jsx", "scss", ".json"],
alias: {
styles: path.resolve(root, "src", "scss"),
canvas: path.resolve(root, "src", "etc", "fileMock"),
ws: path.resolve(root, "src", "etc", "fileMock")
},
plugins: [
new TsconfigPathsPlugin({
configFile: tsconfigPath
})
]
},
devtool: "eval-cheap-source-map",
plugins: [
new BundleTracker({ filename: "./webpack-stats.json" })
]
}
I had a similar issue upgrading from webpack 4 but with a different external library. In my case it was caused by two webpack#5 versions installed at the same time. Check your package-lock.json/yarn.lock and add overrides/resolutions to your package.json if there are several versions. If not — try removing your node_modules folder and installing packages again.

How can I see a list of packages actually used for my application bundle?

I have a problem in treeshaking. It seems like it is not too effective on my project. Is there a way to see a list of the dependencies that is actually used in my webpacked file?
Webpack config:
entry: sourceEntryFile,
mode: 'production', // for webpack 4
target: 'node',
output: {
filename: '[name].js',
path: outputPathFolder,
libraryTarget: 'commonjs',
},
resolve: {
extensions: ['.js', '.json'],
modules: ['node_modules']
},
node: {
__dirname: false,
},
externals: {
'aws-sdk': 'aws-sdk'
},
plugins: (() => {
const plugins = [
new webpack.DefinePlugin({
'global.GENTLY': false
})
];
// plugins.push(new WebpackBundleAnalyzer.BundleAnalyzerPlugin());
return plugins;
})()
npm ls seems to be the closest one. The results show which modules are being used in current project.

Webpack 2: can't resolve node.js native modules

After bundling I have following errors:
Module not found: Error: Can't resolve 'crypto' in //filePath
It can't resolve five modules: crypto, fs, path, vm and constants - from any file which requires them
I thought it could be because of nvm which I use, but I switched to system nodejs via nvm use system command and webpack still throws these errors.
I also thought it could be target property, so I changed it to node, but it didn't help too (anyway I need electron-renderer, not node).
Important note: I've just migrated from webpack 1. It all works well before I migrated. But these are the only errors I have. Moreover, webpack seems to work fine, it even watches files when I pass --watch option.
Here is my webpack.config.js:
const config = {
target: 'electron-renderer',
context: __dirname,
entry: { app: './app.js', vendor: [/*vendors*/]},
cache: true,
devtool: 'source-map',
watch: false
resolve: {
extensions: ['.js', '.json', '.jsx'],
modules: ["node_modules"]
},
module: {
rules: [
{test: /\.html/, loader: 'html-loader'},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader?sourceMap", "less-loader?sourceMap"]
})
},
{
test: /\.css/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader?sourceMap"
})
},
{test: /\.(jpg|png|gif|jpeg|svg|otf|ttf|eot|woff)$/, loader: 'url-loader?limit=10000'}
]
},
plugins: [
new ExtractTextPlugin('styles.[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin({
names: ['commons', 'vendor', 'manifest'],
minChuncks: Infinity
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
hash: false,
inject: 'head',
cashe: true,
showErrors: true
})
],
output: {
publicPath: './',
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js'
}
};
module.exports = config;
The problem was in worker-loader, which is not in my webpack.config.js (I used it directly when importing file). See this issue for details (not fixed yet).

Sass loader not working in webpack

I am trying to get *.scss files to be supported in my webpack configuration but I keep getting the following error when I run the webpack build command:
ERROR in ./~/css-loader!./~/sass-loader!./app/styles.scss
Module build failed: TypeError: Cannot read property 'sections' of null
at new SourceMapConsumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/node_modules/source-map/lib/source-map/source-map-consumer.js:23:21)
at PreviousMap.consumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/previous-map.js:37:34)
at new Input (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/input.js:42:28)
at parse (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/parse.js:17:17)
at new LazyResult (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/lazy-result.js:54:47)
at Processor.process (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/processor.js:30:16)
at processCss (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/processCss.js:168:24)
at Object.module.exports (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/loader.js:21:15)
# ./app/styles.scss 4:14-117
I can't for the life of me figure out why. It's a very basic setup.
I have created a dropbox share with the bare minimum illustrating this:
https://www.dropbox.com/s/quobq29ngr38mhx/webpack.sass.test.zip?dl=0
Unzip this then run:
npm install
webpack
Here is my webpack.config.js file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
}]
}
}
And the index.js entry file:
require('./styles.scss');
alert('foo bar baz');
And the styles.scss file:
body {
background-color: #000;
}
It appears to follow the recommendations of the sass-loader documentation site, but I can't get it to run.
:(
Information about my environment:
node - 0.12.4
npm - 2.10.1
os - OS X Yosemite
I have managed to get another workaround working that doesn't involve editing the css-loader libraries within my npm_modules directory (as per the answer by #chriserik).
If you add '?sourceMap' to the sass loader the css loader seems to handle the output.
Here is my updated configuration:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass?sourceMap'
}]
}
}
P.S. I even expanded this test to include a compass-mixins include, and this worked too.
After having the same issue, I found this: https://github.com/webpack/css-loader/issues/84
Apparently, the solution for now is to manually modify lines 17-19 of /node_modules/css-loader/lib/loader.js with
if(map && typeof map !== "string") {
map = JSON.stringify(map);
}
This fixed the problem for me.
The problem is solved by setting source-map option to true (as seen in other answers).
But in case you find messy passing options in the query string there is an alternative;
for configuring the sass loader you can create a sassLoader property in the webpack config object:
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass'
// loader: ExtractPlugin.extract('style', 'css!sass'),
}]
},
sassLoader: {
sourceMap: true
},
}

Resources