Path mapping in Javascript? - javascript

I'm currently working on a javascript project. I usually use typescript and ts has the path mapping feature. Is there something similar in javascript ?
TS path mapping:
"compilerOptions": {
"baseUrl": "src",
...
"paths": {
"#app/*": ["app/*"],
"#config/*": ["app/_config/*"],
"#environment/*": ["environments/*"],
"#shared/*": ["app/_shared/*"],
"#helpers/*": ["helpers/*"]
},
...

In Webpack this feature is available via resolve.alias. The configuration is similar, for example via webpack.config.js:
const path = require('path');
module.exports = {
resolve: {
alias: {
"#app": path.resolve(__dirname, 'app/'),
"#config": path.resolve(__dirname, 'app/config/'),
"#environment": path.resolve(__dirname, 'environments/'),
// Etc
},
},
};

Related

digest-fetch and webpack - fetch is not a function

The Problem
TypeError: fetch is not a function
at DigestClient.fetch (webpack-internal:///./node_modules/digest-fetch/digest-fetch-src.js:48:24)
at User.create (webpack-internal:///./node_modules/mongodb-atlas-api-client/src/user.js:53:26)
at Function.createOrgDBUser (webpack-internal:///./src/OrgUtils.ts:87:51)
at Function.createOrg (webpack-internal:///./src/apis/OrgAPI.ts:373:39)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async APIResponse.processHandlerFunction (webpack-internal:///./node_modules/apilove/lib/APIResponse.ts:27:31)
That's the error I'm getting trying to use mongodb-atlas-api-client#2.3.1 to create indexes on a collection. I'm seeing this error locally and in aws-lambda.
atlasClient.user.create({...})
I use webpack to bundle my api so I think the issue is in how I'm bundling but in my research I haven't been able to come up with a solution.
digest-fetch, used by mongodb-atlas-api-client, uses node-fetch in absence of the native fetch function. However, I believe my webpack configuration coupled with the way digest-fetch imports the library is what's causing the issue.
The following line of code is from node-modules/digest-fetch/digest-fetch-src.js:8
if (typeof(fetch) !== 'function' && canRequire) var fetch = require('node-fetch')
If I change that to the below, everything works fine. In other words, it's importing the module not the main exported fetch function from node-fetch.
if (typeof(fetch) !== 'function' && canRequire) var fetch = require('node-fetch').default
The node-fetch/package.json describes three entry points.
"main": "lib/index.js",
"browser": "./browser.js",
"module": "lib/index.mjs",
I think what's happening is my webpack configuration is telling webpack to use the .mjs module entry point to build its output from node-fetch, which does export default fetch;.
My webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const NodemonPlugin = require('nodemon-webpack-plugin')
const ZipPlugin = require('zip-webpack-plugin')
module.exports = (env, argv) => {
const config = {
target: 'node',
watchOptions: {
ignored: ['node_modules', '*.js', '*.js.map', '*.d.ts'],
},
entry: './src/APIHandler.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: `APIHandler.js`,
libraryTarget: 'commonjs',
},
optimization: {
minimize: false,
// minimizer: [new TerserPlugin({})],
},
resolve: {
extensions: ['.ts', '.json', '.mjs', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
allowTsInNodeModules: true,
},
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin([
{ from: path.join(__dirname, 'src/certs'), to: path.resolve(__dirname, 'dist', 'certs') },
]),
new NodemonPlugin(),
],
}
// eslint-disable-next-line no-console
console.log({ mode: argv.mode })
if (argv.mode === 'development') {
config.devtool = 'eval-cheap-module-source-map'
}
if (argv.mode === 'production') {
config.plugins.push(
new ZipPlugin({
filename: 'handler',
})
)
}
return config
}
FWIW, here's the version of each library currently installed in my node_modules. I'm using node v12.22.7 locally.
"digest-fetch": "1.2.1",
"mongodb-atlas-api-client": "2.31.0",
"node-fetch": "2.6.7",
"webpack": "4.46.0"
The Question
What am I missing? What change do I need to make to my webpack.config.js to have the require properly resolve to the main module export from node-fetch?
NOTE: In my research I've found other people having this problem but no resolutions that have helped me.
The solution was pretty simple. I added mainFields to the webpack config's resolve property.
resolve: {
extensions: ['.ts', '.json', '.mjs', '.js'],
mainFields: ['main', 'module'],
}
This tells webpack to first use the main property of a module's package.json, then fallback to the module property if it's not found.
For more information, see webpack's documentation.

Webpack: use data from parent directory without copying

I have a project folder structured like this:
project-name/
data/
data.csv
dist/
index.js
src/
index.js
And want a remote directory like this:
project-name/
data/
data.csv
dist/
index.js
> `doSomething("../data/data.csv")`
How do I make this work in both webpack-dev-server and in the production path? If I use copywebpack plugin, then the data goes inside the dist/, which I don't want. But if I use a relative directory without copying the data, then the build fails.
Actually, you should use Webpack csv-loader in your Webpack configuration file like below:
module: {
rules: [
{
test: /\.csv$/,
loader: 'csv-loader',
options: {
dynamicTyping: true,
header: true,
skipEmptyLines: true,
},
},
],
},
And then use it inside your code like below:
import csvPath from './project-name/data/foo.csv'
Can you use an alias?
webpack.config.js:
const path = require("path");
module.exports = {
...
resolve: {
alias: {
Data: path.resolve(__dirname, "./project-name/data/"),
},
},
}
src/index.js:
import data from "Data/data.csv"
Have you tried excluding it in the test? Something like this:
{
entry: "./src/index.js",
module: {
rules: [
{
test: /\.js$/,
use: ["babel-loader or whatever loader you use"],
},
{
test: /\.csv$/,
exclude: ["./data/"],
},
],
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
},
},
There is a similar question on how to not bundle files in webpack here
You can use context param.
new CopyWebpackPlugin(
[{
context: './source/',
from: '**/*.html',
to: './public',
force: true
}], {
copyUnmodified: true
}
)

Babel module resolver not working with react-native

My babel module resolver is not working with React-Native (neither does intellij in VScode)
Here, Is my babel config
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./'],
alias: {
'#assets': './src/assets',
'#modules': './src/modules',
'#config': './src/config',
'#utils': './src/utils',
},
},
],
],
};
And jsconfig.json
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#assets": ["./assets"],
"#modules": ["./modules"],
"#config": ["./config"],
"#utils": ["./utils"]
}
}
}
I changed import for one of my files and this is the error I get when I executed the build command from Xcode
Error: Error loading assets JSON from Metro. Ensure you've followed
all expo-updates installation steps correctly. Unable to resolve
module ../../modules/store/components/Filters from
src/utils/Router.js:
None of these files exist:
Where I imported the file like this
import Filters from '#modules/store/components/Filters';
I had the same problem, I just removed the '#' from my aliases and it seems working fine now.
Here is my babel.config.js
module.exports = function (api) { ■ File is a CommonJS module; it may be converted to an ES6 module.
api.cache(true);
return {
presets: ["babel-preset-expo"],
plugins: [
[
require.resolve("babel-plugin-module-resolver"),
{
root: ["./src/"],
alias: {
// define aliases to shorten the import paths
components: "./src/components",
containers: "./src/containers",
contexts: "./src/contexts",
interfaces: "./src/interfaces",
organizer: "./src/screens/organizer",
screens: "./src/screens",
},
extensions: [".js", ".jsx", ".tsx", ".ios.js", ".android.js"],
},
],
],
};
};
Try resetting the cache, if above suggested answers don't work
react-native start --reset-cache
This worked for me. For more info see here
Change your module-resolver's root to ['./src/']:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./src/'], // <-- here ✅
alias: {
'#assets': './src/assets',
'#modules': './src/modules',
'#config': './src/config',
'#utils': './src/utils',
},
},
],
],
};

eslint error showing with webpack alias

In my webpack config. I defined aliases
alias: {
components: 'src/components/',
config: 'src/config/'
}
When I import a module from this path an eslint error occurred.
import ShadowWrapper from 'components/ShadowWrapper'
error 'components' should be listed in the project's dependencies. Run 'npm i -S components' to add it import/no-extraneous-dependencies
Thanks, Pranav for the solution to this issue!
I add some code to this post to make it more practical for others.
First of all, in webpack config file I had defined this alias:
alias:{
components: path.resolve(__dirname, "src", "components")
}
That allow me to import components in my app in that way:
import NewsFeed from 'components/NewsFeed'
I have installed eslint-import-resolver-webpack plugin and put below code into .eslintrc.js or .eslintrc file :
settings: {
'import/resolver': {
alias: {
map: [
['components', './src/components']
]
}
}
That's it after running linter I got rid of Unable to resolve path to module 'components/NewsFeed' error message
Hope it will be helpful for some of you!
Here is what worked for me:
I installed eslint-import-resolver-alias as dev dependency:
npm install eslint-plugin-import eslint-import-resolver-alias --save-dev
In the Webpack config (in my case, it was Vue config, which is merged with Webpack config by Vue-cli), I added a few aliases:
resolve: {
extensions: ['.js', '.vue', '.json', '.less'],
alias: {
Site: path.resolve(__dirname, 'src/site'),
Admin: path.resolve(__dirname, 'src/admin'),
Common: path.resolve(__dirname, 'src/common'),
Assets: path.resolve(__dirname, 'src/common/assets'),
Configs: path.resolve(__dirname, 'src/common/configs'),
Style: path.resolve(__dirname, 'src/common/style')
}
}
In the .eslintsrc (or .eslintsrc.js, if you use that), I added the plugin and maps for these aliases, as follows:
"extends": ["plugin:import/recommended"],
"settings": {
"import/resolver": {
"alias": {
"map": [
["Site", "./src/site"],
["Admin", "./src/admin"],
["Common", "./src/common"],
["Assets", "./src/common/assets"],
["Configs", "./src/common/configs"],
["Style", "./src/common/style"]
]
},
"extensions": [".js", ".less", ".json", ".vue"]
}
}
I have added extensions for clarity and some good measures, which you can choose to not use for yourself.
Optional:
If you use VS Code and want these aliases working with the path intellisense, add a file jsconfig.json at the root, and specify your alias paths:
{
"compilerOptions": {
"target": "esnext",
"allowSyntheticDefaultImports": false,
"baseUrl": "./",
"paths": {
"~/*": ["src/*"],
"Root/*": ["src/*"],
"Site/*": ["src/site/*"],
"Admin/*": ["src/admin/*"],
"Common/*": ["src/common/*"],
"Assets/*": ["src/common/assets/*"],
"Configs/*": ["src/common/configs/*"],
"Style/*": ["src/common/style/*"]
}
},
"exclude": ["node_modules", "dist"]
}
There are additional settings for React and Typescript. Check the documentation at official site.
This issue can be resolved by using the eslint-import-resolver-webpack
Another way, without mapping aliases between webpack.config.js and .eslintrc.
You can use eslint-import-resolver-webpack and setup you .eslintrc file like this:
{
"extends": [
"plugin:import/recommended"
],
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"],
"moduleDirectory": [
"node_modules",
"src"
]
}
}
}
}

Angular 4 universal app with #angular/cli with third party (library/component) compilation

I am trying to implement server side rendering using angular universal. With followed this post angular-4-universal-app-with-angular-cli and this cli-universal-demo project, I encountered a problem as below.
When node starts dist/server.js it shows an error:
(function (exports, require, module, __filename, __dirname)
{ export * from ‘./scn-filter-builder’
scn-filter-builder is my module. It's written in angular2/typescript and node.js doesn't understand it.
The question is that can I set to universal so it will compile packages from node_module to es5 by itself? Or I need to compile my component into es5?
So I ended up tackling something similar to this by compiling it with Webpack. I just added a webpack.config.js with the following:
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: {
server: './src/server.ts'
},
resolve: {
extensions: ['.ts', '.js']
},
target: 'node',
externals: [nodeExternals({
whitelist: [
/^ngx-bootstrap/
]
})],
node: {
__dirname: true
},
output: {
path: path.join(__dirname, 'server'),
filename: '[name].js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{ test: /\.ts$/, loader: 'ts-loader' }
]
}
}
Add the library that needs to be compiled in the nodeExternals -> whitelist area. In my case it was ngx-bootstrap. Then just run webpack to compile your file.

Categories