Programmatic Webpack & Jest (ESM): can't resolve module without '.js' file extension - node.js

I'm using webpack programmatically, with typescript, ESM, and jest. In a jest test I'm getting errors for not including a .js file extension when importing ES modules. For example:
Module not found: Error: Can't resolve 'modulename' in '/path/components'
Did you mean 'modulename.js'?
BREAKING CHANGE: The request 'modulename' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
The module in question does indeed have "type": "module" set in its package.json. I have tried adding .js to the import, and it doesn't help.
I'm invoking jest with:
node --experimental-vm-modules --experimental-specifier-resolution=node node_modules/jest/bin/jest.js
as is recommended in the docs (everything else works except webpack). Note that I have tried with and without --experimental-specifier-resolution=node (this has helped in other similar circumstances).
Any thoughts on how to get webpack to work? Thanks in advance!
Note: everything was working until it was all converted to ESM! Now only programmatic webpack isn't working.
Webpack config:
{
entry,
target: 'web',
output: {
path: outputDir,
filename: '[name].js',
},
mode: process.env.NODE_ENV as 'development' | 'production' | 'none' | undefined,
resolve: {
extensions: [
'.ts',
'.tsx',
'.js',
'.jsx',
'.ttf',
'.eot',
'.otf',
'.svg',
'.png',
'.woff',
'.woff2',
'.css',
'.scss',
'.sass',
],
},
module: {
rules: [
{
test: /\.(ttf|eot|otf|svg|png)$/,
loader: 'file-loader',
},
{
test: /\.(woff|woff2)$/,
loader: 'url-loader',
},
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
sourceType: 'unambiguous',
presets: [
[
'#babel/preset-env',
{
corejs: '3.0.0,',
useBuiltIns: 'usage',
},
],
'#babel/preset-react',
'#babel/preset-typescript',
],
plugins: [
'css-modules-transform',
[
'babel-plugin-react-scoped-css',
{
include: '.scoped.(sa|sc|c)ss$',
},
],
'#babel/plugin-proposal-class-properties',
],
},
},
{
test: /\.(sc|c|sa)ss$/,
use: [
'style-loader',
'css-loader',
'scoped-css-loader',
'sass-loader',
],
},
],
},
}

Ok so I found the solution here.
Basically, had to add 2 things to the webpack config under module.rules:
{
test: /\.m?js/,
type: "javascript/auto",
},
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},

#nerdlinger answer worked for me. I had this webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
],
}
...
}
and i changed it to this
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
},
resolve: {
fullySpecified: false,
}
}
],
}
...
}

Related

Webpack Babel build fails when importing files outside entry path

I have this project that i'm already using webpack + babel to build. I've hit a wall since what i want to do is share some constants between my node (server) and my react app (front-end).
My project structure is this
- app
- internals
- webpack
- different webpack configs (node, react-dev, react-production etc)
- server
- shared
- .babelrc
I've put some "constants" files into the shared folder that I use both from my app and from my server.
When I try to build my server I get this
ERROR in ./shared/reports.constants.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
TypeError: Cannot read property 'code' of null
at transpile (C:\Users\XXX\Desktop\XXX\XXX\node_modules\babel-loader\lib\index.js:70:21)
at Object.module.exports (C:\Users\XXX\Desktop\XXX\XXX\node_modules\babel-loader\lib\index.js
:173:20)
Below is my webpack config file. Any ideas what might be wrong ?
{
mode: 'production',
target: 'node',
externals: nodeExternals(),
entry: {
server: [path.join(process.cwd(), 'server/index.js')],
},
output: {
filename: '[name].js',
path: path.resolve(process.cwd(), 'build'),
// sourceMapFilename: '[name].js.map',
},
devtool: 'hidden-source-map',
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{ fallback: 'style-loader', use: { loader: 'css-loader', options: { minimize: true } } }),
},
{ test: /\.jpg$/, use: [{ loader: 'file-loader', options: { name: '/images/[name].[ext]' } }] },
{ test: /\.md$/, use: [{ loader: 'markdown-with-front-matter-loader' }] },
{
test: /\.js$/,
exclude: [/node_modules/],
include: [/server/, /shared/],
use: [
'babel-loader',
{
loader: 'webpack-preprocessor-loader',
options: {
debug: process.env.NODE_ENV !== 'production',
directives: {
secret: false,
},
params: {
ENV: process.env.NODE_ENV,
DEBUG: process.env.NODE_ENV !== 'production',
PRODUCTION: process.env.NODE_ENV === 'production',
ENVIRONMENT: process.env.ENVIRONMENT,
},
verbose: false,
},
},
],
},
],
},
plugins
etc
}
.babelrc file
{
"presets": [
"#babel/preset-env"
],
"plugins": [
"react-hot-loader/babel",
"#babel/transform-runtime",
"transform-html-import-to-string"
]
}
I've added the /shared/ to the includes rules.
Thank you in advance
For some reason I already had a babel.config.js + the babelrc. All I had to do was go into the babel.config.js and add the shared folder to be included in the env => production.
Thank you for your time

Why can't I resolve nodejs default modules when using preset-env node?

I am writing a plugin for an app that runs Chromium Embedded Framework (CEF) with an older version of Node.
I threw webpack & babel into the app. When I run webpack, it fails on a file that has const fs = require('fs');, or any other default node package. This is happening both for my code and dependencies:
Module not found: Error: Can't resolve 'fs' in '/Users/me/repositories/myrepo/node_modules/chokidar'
My .babelrc is the following:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"node": true
}
}
]
]
}
My webpack config is essentially:
module.exports = {
entry: './src/main.jsx',
mode: process.env.NODE_ENV,
devtool: isDev ? 'eval-source-map' : false,
output: {
path: PLUGINDIR,
filename: 'main.js',
libraryTarget: 'umd'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: ['transform-react-jsx']
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.css']
}
};
webpack config also needs target: 'node'. Doing it just in .babelrc was not enough.

Webpack semantic-ui-less Module build failed

I have been following various tutorials on importing semantic-ui-less into a webpack project.
However, whenever I have completed the different tutorials I am getting the same error:
Module build failed:
module.exports = __webpack_public_path__ + "static/media/reset.b0bc6c14.less";
^
Unrecognised input
in /Users/benflowers/Projects/candidate/candidate-ui-cra/node_modules/semantic-ui-less/definitions/globals/reset.less (line 1, column 15)
Is this an issue with my webpack config - I have an ejected create-react-app webpack config with some additional loaders:
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' },
{ loader: 'less-loader' }
]
}),
exclude: [/[\/\\]node_modules[\/\\]semantic-ui-less[\/\\]/]
},
// for semantic-ui-less files:
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader' },
{
loader: 'semantic-ui-less-module-loader',
// you can also add specific options:
options: { siteFolder: path.join(__dirname, 'src/site') }
}
]
}),
include: [/[\/\\]node_modules[\/\\]semantic-ui-less[\/\\]/]
},
// loader for static assets
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
use: {
loader: 'url-loader',
options: {
limit: 10240,
absolute: true,
name: 'images/[path][name]-[hash:7].[ext]'
}
},
include: [path.join(__dirname, 'src'), /[\/\\]node_modules[\/\\]semantic-ui-less[\/\\]/]
}
as per https://github.com/gadyonysh/semantic-ui-less-module-loader
I had the similar issue.
I just added to webpack config
ALIAS
resolve: {
...
alias : {
'../../theme.config$': path.join( __dirname, '../src/assets/theme/theme.config' )
}
},
LESS LOADER
{
test: /\.less$/,
use : ExtractTextPlugin.extract( {
fallback: [ {
loader: 'style-loader',
} ],
use : [ 'css-loader', 'resolve-url-loader', 'less-loader', 'postcss-loader' ]
} )
},
and exclude
{
exclude: [
/\.(config|overrides|variables)$/,
/\.html$/,
/\.(js|jsx)$/,
/\.css$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
/\.jpe?g$/,
/\.png$/,
/\.scss$/,
],
loader: require.resolve( 'file-loader' ),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
please pay attention to line
/.(config|overrides|variables)$/,
Adding this to your less exclude should do the trick :
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/, /\.(less|config|variables|overrides)$/],

Webpack suppress eslint warnings on browser console

I`ve finished configuring my eslint rules and refactoring project files according to my rules. Thing is that I have some warnings that I may want to leave there for a while. But my problem is that warnings are being shown on browser console, what makes development impossible.
Below, my webpack config:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const context = path.resolve('.');
module.exports = {
context: context,
entry: './src/client.js',
output: {
path: path.join(context, 'build/client'),
publicPath: '/static/',
filename: '[name]-[hash].js'
},
module: {
preLoaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader'
},
],
loaders: [{
test: /(?:node_modules).+\.css$/,
loader: 'style!css'
}, {
test: /\.scss$/,
loader: ExtractTextPlugin.extract([
'css-loader',
'postcss-loader',
'sass-loader',
'sass-resources'
])
}, {
test: /\.js$/,
loader: 'babel',
exclude: /(node_modules)/
}, {
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/font-woff"
}, {
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/font-woff"
}, {
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=application/octet-stream"
}, {
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: "file"
}, {
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: "url?limit=10000&mimetype=image/svg+xml"
}, {
test: /\.json$/,
loader: 'json'
}]
},
postcss: function() {
return [
require('autoprefixer')
];
},
sassResources: [
path.resolve(__dirname, '../src/stylesheets/base/_variables.scss'),
path.resolve(__dirname, '../src/stylesheets/base/_mixins.scss')
],
devServer: {
watchOptions: {
aggregateTimeout: 1000
}
},
plugins: [
new ExtractTextPlugin("[name]-[hash].css"),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'local')
})
],
devtool: "cheap-module-source-map"
};
I have no problem with errors being displayed on browser console, but is there a way to suppress warnings ONLY on browser console and not on the node terminal?
https://devhub.io/repos/coryhouse-eslint-loader
In my webpack.config.js I have options setup:
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
['es2015', {modules: false}],
'react'
],
plugins: [ 'react-hot-loader/babel' ]
}
}, {
loader: 'eslint-loader',
options: {
quiet: true
}
}
]
}
]
}
The last line is quiet: true, which is how it suppresses the warnings.
Use
clientLogLevel: "none"
in the devServer config
Doc: https://webpack.js.org/configuration/dev-server/#devserverclientloglevel
devServer.clientLogLevel
string: 'none' | 'info' | 'error' | 'warning'
When using inline mode, the console in your DevTools will show you messages e.g. before reloading, before an error or when Hot Module Replacement is enabled. Defaults to info.
devServer.clientLogLevel may be too verbose, you can turn logging off by setting it to 'none'.
webpack.config.js
module.exports = {
//...
devServer: {
clientLogLevel: 'none'
}
};
Usage via the CLI
webpack-dev-server --client-log-level none

Webpack and TypeScript: Cannot resolve module 'child_process' in node.d.ts

I tried to get webpack, typescript and react.js working together via awesome-typescript-loader, but I constantly get errors.
I am using awesome typescript loader at Version 0.3.0-rc.2 and webpack 1.8.9
This is my webpack.config.js:
module.exports = {
entry: './ui/index.ts',
output: {
path: __dirname + '/build-ui',
filename: 'app.js',
publicPath: 'http://localhost:8090/assets'
},
module: {
loaders: [
{
test: /\.jsx$/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
loader: "style-loader!css-loader!sass-loader"
},
{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=8192'
},
{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
}
]
},
resolve: {
extensions: ['', '.js', '.jsx', '.ts']
}
};
When I run the webpack dev server and my index.ts looks like this:
alert('hello');
It states the following error:
ERROR in ./ui/index.ts
/Users/..../typings/node/node.d.ts:29:12
Subsequent variable declarations must have the same type. Variable 'require' must be of type 'WebpackRequire', but here has type '{ (id: string): any; resolve(id: string): string; cache: any; extensions: any; main: any; }'.
Same when I put in the reference path.
When I try to import the React.js via import React = require('react'); it states:
ERROR in ./ui/index.ts
Module build failed: Cannot resolve module 'child_process' in /..../typings/node
Required in /..../typings/node/node.d.ts
I copied the node.d.ts file from the loader repo, still no luck.
Has anybody been able to get this combination work smoothly? Or should I just use a different web packager?
I'd really would like to get it to work with webpack.
All you're missing is a key target: 'node'.
This makes sure that the environment you are targeting is Node.js and not the browser, and will therefore ignore native dependencies.
Final Config:
module.exports = {
entry: './ui/index.ts',
target: 'node',
output: {
path: __dirname + '/build-ui',
filename: 'app.js',
publicPath: 'http://localhost:8090/assets'
},
module: {
loaders: [
{
test: /\.jsx$/,
loader: 'jsx-loader?insertPragma=React.DOM&harmony'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.scss$/,
loader: "style-loader!css-loader!sass-loader"
},
{
test: /\.(png|jpg)$/,
loader: 'url-loader?limit=8192'
},
{
test: /\.ts$/,
loader: 'awesome-typescript-loader'
}
]
},
resolve: {
extensions: ['', '.js', '.jsx', '.ts']
}
};
You could consider using a different webpack TypeScript loader. I know a few had issues with node stuff. There are also a couple starter kits that may help out.
Disclaimer: I'm the maintainer of ts-loader.
Try creating a tsconfig.json file.
For example, as you are using awesome-typescript-loader this should work:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true,
"noEmitHelpers": true
},
"exclude": [
"node_modules"
],
"awesomeTypescriptLoaderOptions": {
"forkChecker": true
},
"compileOnSave": false,
"buildOnSave": false,
"atom": { "rewriteTsconfig": false }
}

Resources