Jest is unable to import default export from index file of absolute path: "ENOENT: no such file or directory" - node.js

I set up absolute path in my node.js typescript project.
Here's the content of my Jest config file (jest.config.js):
const { pathsToModuleNameMapper } = require('ts-jest');
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
transform: {
'^.+\\.ts?$': 'ts-jest',
},
transformIgnorePatterns: ['<rootDir>/node_modules/'],
modulePaths: ['./src'],
moduleNameMapper: pathsToModuleNameMapper({
'#/*': ['*'],
}),
clearMocks: true,
};
The above config enables Jest to understand absolute path in my code.
Below is a sample of my project structure. I have a events directory that has an index.ts file like so:
src
└─ events
└─ index.ts
When I import the default export like so:
import events from '#/events'
and run Jest it throws: "ENOENT: no such file or directory, open 'events'"
but it works if I import the default export like so
import events from '#/events/index'
How do I get Jest to recognize the index.ts file in the absolute path without explicitly specifying it?
Jest should be able to detect and use the index file of the absolute path when I import like so:
import events from '#/events'

Try to add this in your tsconfig.json
{
"compilerOptions": {
"baseUrl": "./"
},
}

Related

How to configure react typescript project having folder paths accessible like '#components/'

I want to change the relative url imports for react-typescript project. Basically from this crap ../../../contexts/AuthContext to just clean #contexts/AuthContexts.
I have tried the following with tsconfig.json :
"compilerOptions": {
"paths": {
"#components/*": ["src/components/*"],
"#contexts/*": ["src/contexts/*"]
}
}
But I am still getting error like #contexts/AuthContexts not found. And yes I can confirm that there is a file called AuthContext in that location with exports as AuthProvider.
I have created this app with npm create vite#latest using typescript as a template.
Any help will be highly appreciated.
You need to set resolve.alias in vite.config.ts file
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
"#components": path.resolve(__dirname, "src/components"),
},
},
});

Bundle NPM Package so it has different import paths with Vite and Typescript

How can I bundle my NPM package in a way that I can have different import paths for different parts of the package? I have found webpack approaches, but I am using Vite and TS.
My package looks like this:
- src
- atoms
- molecules
- organism
- index.ts (currently simply imports and exports everything)
Now I can use this currently like this
import { Button } from '#mypackage/library'
How can I do it, so I get this outcome:
import { Button } from '#mypackage/library/atom'
Here is the relevant part of my package.json
{
"entry": "src/index.ts",
"main": "dist/index.cjs.js",
"module": "dist/index.es.js",
"types": "dist/index.d.ts",
"files": [
"dist",
"src"
],
"exports": {
".": {
"import": "./dist/index.es.js",
"require": "./dist/index.cjs.js",
"types": "./dist/index.d.ts"
},
"./package.json": "./package.json",
"./atoms": "./src/atoms/index.ts",
"./molecules": "./src/molecules/index.ts",
"./organisms": "./src/organisms/index.ts",
"./theme": "./src/theme/index.ts"
},
}
Here is my vite.config.ts
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
formats: ['es', 'cjs'],
name: '#workdigtital/component-library-react',
fileName: (format) => `index.${format}.js`
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: {
react: 'React',
'react-dom': 'ReactDOM'
},
exports: 'named'
}
}
},
plugins: [react(), dts({ insertTypesEntry: true })],
resolve: {
alias: {
'#': path.resolve(__dirname, './src')
}
}
});
If I currently try an import like this, inside another project (Laravel+React), in which installed the library.
import { ThemeProvider } from '#workdigital/component-library-react/theme';
I get the following run time error (But no Typescript errors, even IntelliSense is working):
Failed to load url /resources/js/theme/ThemeProvider (resolved id: /resources/js/theme/ThemeProvider). Does the file exist?
My resulting Dist folder looks like this:
You can't have TypeScript exports, this simply won't work. An npm package should have only JS exports.
If you want to be able to selectively import different parts of your package, you must transpile them to different files.
rollup can do it, but it is lots of work, as you will have to set up a separate target for each exported file. Normally you use rollup to create a single bundle, this what this tool is made for.
tsc with a tsconfig.json will be a much better choice in your case. It does this by default, you only need to specify the output directory and it will produce a separate file for each source.
There is an excellent guide on the TypeScript site about packaging TypeScript libraries, you should probably start there.

Vite: Including files in build output

This is a Vue 3 + Vuetify + TS + Vite + VSCode project.
I'm trying to bundle an XML file in the production build. Some transformation needs to be applied on the file before spitting it out. Found this Vite plug-in that can do transformations. But unfortunately, it doesn't seem to touch XML files in any way. If I put my XML file in public folder, it gets copied to the build output, but is not processed by the transformation plugin. If I put it in assets or somewhere else under src, it is simply ignored.
How can I ask Vite to include certain file(s) in the build output and pass it through transformation?
Note: Before I migrated the project to Vite, I was using Vue 2 and WebPack, where I could use the well-known CopyWebpackPlugin to perform this transformation. Haven't been able to find locate its Vite equivalent till now.
You may want to just write a script to do the transformation and add it to your npm scripts. I created a simple chrome extension to play around with VITE. Having multiple html files was pretty simple:
import { defineConfig, BuildOptions } from 'vite'
import vue from '#vitejs/plugin-vue'
const { resolve } = require('path')
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
build: {
rollupOptions: {
input: {
main: resolve(__dirname, 'index.html'),
popup: resolve(__dirname, 'popup/index.html'),
options: resolve(__dirname, 'options/index.html'),
},
}
}
})
But I had to create a separate vite config file to process the background script since it had special configuration (didn't want hashing so I could specify the name in my manifest, esm module format), and it takes the typescript and outputs 'background.js' in the public folder:
import { defineConfig } from 'vite'
const { resolve } = require('path')
// https://vitejs.dev/config/
export default defineConfig({
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, 'background.ts'),
output: {
format: "esm",
file: "public/background.js",
dir: null,
}
}
}
})
You could simply have the xml file in your src folder and run a special script (create a 'scripts' folder maybe) to do the transform and store the result in the public folder where vite will pick it up and copy it to the dist folder. Your 'build' script in package.json could look something like this:
"scripts": {
"build": "node scripts/transform-xml.mjs && vite build",
},
Author of the package has introduced a new option named replaceFiles in the version 2.0.1 using which you can specify the files that will be passed through the transform pipeline. I can now do the following in my vite.config.js to replace variables in my output manifest.xml file after build:
const replaceFiles = [resolve(join(__dirname, '/dist/manifest.xml'))];
return defineConfig({
...
plugins: [
vue(),
transformPlugin({
replaceFiles,
replace: {
VERSION_NUMBER: process.env.VITE_APP_VERSION,
SERVER_URL: process.env.VITE_SERVER_URL,
},
...
}),
...
});

React: Absolute Paths from Root Folder using ViteJS with TypeScript

So, in React, using vite, I'm trying to do the following structure, but seems I can't get it to work because I'm missing a concept or something, so the structure is as follows:
src/utils
src/routes
src/index.tsx
src/main.tsx
And on the index.tsx, I want to import utils and routes, and then call them at any root level as following: import {Routes, Utils} from "#", but the way I did is not working.
Meanwhile, this is how I configured it with vite:
resolve: {
alias: {
"#": path.resolve(__dirname, "src"),
},
},
Make sure index.tsx exports everything from src/utils and src/routes:
// src/index.tsx
export * from './routes'
export * from './utils'
And configure TypeScript with a path alias for #:
// tsconfig.json
{
"compilerOptions": {
"paths": {
"#": ["./src"], // 👈 needed for barrel imports from '#'
"#/*": ["./src/*"]
}
}
}
demo

jest.config.ts: "registerer.enabled is not a function" error when running jest from Github Actions

When running jest locally, it instantiates my app and runs tests without any issues.
When running jest inside github actions, I'm getting this error:
Error: Jest: Failed to parse the TypeScript config file /home/runner/work/myproject/myproject/jest.config.ts
TypeError: registerer.enabled is not a function
at readConfigFileAndSetRootDir (/home/runner/work/myproject/myproject/node_modules/#jest/core/node_modules/jest-config/build/readConfigFileAndSetRootDir.js:118:13)
the package.json script entry is just:"test": "jest"
and the jest.config.ts file is:
import tsJestUtils from 'ts-jest/utils'
import tsConf from './tsconfig.json'
const rootDir = __dirname
const { pathsToModuleNameMapper } = tsJestUtils
const {
compilerOptions: { paths },
} = tsConf
const config = {
preset: 'ts-jest',
testEnvironment: 'node',
roots: [`${rootDir}/src`],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
moduleNameMapper: pathsToModuleNameMapper(paths, {
prefix: `${rootDir}/src`,
}),
}
export default config
So I just bypassed use of typescript for my jest config entirely, and went with an equivalent jest.config.js file based on the docs. Works in Github Actions now, runner does not fail! \o/
I am still not sure what the issue was, but I think ts-node just wasn't processing the config file properly. I feel like the actual failure was with the attempt to load a .ts config file, specifically at this point in the source code when it tries to call registerer.enabled().
It can be fixed by upgrading to "ts-node": "^8.5.0"

Resources