How to debug import of a javascript function in React? - javascript

I have some functions in a javascript file (helpers.js) that are imported into a react file (caller.jsx).
helpers.js:
async function one() {
// ...
}
function two() {
// ...
}
module.exports = { one, two }
caller.jsx:
const { one, two } = require("../utils/helpers")
When I run my local React server (npm run start), everything works fine. I can use the app and it works.
When I run a production build (npm run build) and serve up the javascript from that build, it doesn't work, and there's an error message in the console:
main.d780c23e.chunk.js:1 Uncaught TypeError: Cannot assign to read only property 'exports' of object '#<Object>'
at Module.<anonymous> (main.d780c23e.chunk.js:1)
at Module.228 (main.d780c23e.chunk.js:1)
at i ((index):3)
at Module.375 (main.d780c23e.chunk.js:1)
at i ((index):3)
at t ((index):3)
at Array.r [as push] ((index):3)
at main.d780c23e.chunk.js:1
And the compiled code in the browser shows the problem at the exports of helpers.js, right at the equals sign (=):
b.exports = {
one: function() { ... },
two: function() { ... }
}
}
I have also tried importing the symbols in caller.jsx:
import { one, two } from "../utils/helpers"
In that case, the production build complains that the symbol is not exported.
./src/hooks/caller.jsx
Attempted import error: 'two' is not exported from '../utils/helpers'.
And if I delete two, then it complains about one.
It seems the CommonJS style of code (with module.exports) isn't working in the ESModule style of code (with import).
However, I have some other files (call them caller2.jsx and helper2.js) where it is working for helper2.js to use module.export and caller2.jsx to use an import statement.
I am flummoxed about how to tell what's going in.
It IS exported, damnit! Why does only the production compiler say it's not?
Versions: node v16.10.0, npm 7.24.0, react 17.0.2, react-scripts 4.0.3.
EDIT: Some build info: we build using npm. Here are the scripts in package.json:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
}
As an example, here is the full output of build:
$ npm run build
> myapp#0.1.0 build
> react-scripts build
Creating an optimized production build...
Compiled successfully.
File sizes after gzip:
421.79 KB build/static/js/2.9462f3d3.chunk.js
23.57 KB build/static/css/2.0a9ec390.chunk.css
20.85 KB (+1 B) build/static/js/main.2d21dfa5.chunk.js
2.49 KB build/static/css/main.8d569477.chunk.css
1.73 KB build/static/js/3.2618e91d.chunk.js
1.17 KB build/static/js/runtime-main.2616b467.js
The project was built assuming it is hosted at /.
You can control this with the homepage field in your package.json.
EDIT 2: We are using hardhat, so we cannot use ESModule exports. See for example this github issue, or this stackoverflow question.

Related

DevExtreme in Nuxt3 failing during build

I am trying to include DevExtreme UI components into Nuxt 3 project. I took basic Nuxt3 app generated via npx nuxi init nuxt-app and started with bending it.
This is my test component with very basic DevExtreme menu:
<template>
<div id="container">
<dxMenu>
<dxItem icon="home" />
<dxItem text="O aplikaci" />
<dxItem icon="key" />
</dxMenu>
</div>
</template>
<script lang="ts">
import DxMenu, { DxItem } from 'devextreme-vue/menu.js';
import { defineComponent } from 'vue'
export default defineComponent({
components: {
DxMenu, DxItem
}
})
</script>
Then I just render the component in my app.vue. I have no other configuration related to that (apart from importing DevExtreme css file via nuxt.config.ts).
My nuxt.config.ts looks just like this:
import { defineNuxtConfig } from 'nuxt'
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
css : [
'#/assets/css/dx.generic.zdd-scheme.css'
]
})
I was quite successful for dev environement - running npm run dev works like charm. But when I try npm run build it always fails.
The output looks like this:
i Client built in 11430ms 13:38:43
i Building server... 13:38:43
√ Server built in 4482ms 13:38:47
√ Generated public .output/public nitro 13:38:47
start Building server... nitro 13:38:47
ERROR Rollup error: Error: Cannot find module devextreme/ui/menu imported from file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nuxt/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules
ERROR Error: Cannot find module devextreme/ui/menu imported from file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/node_modules, file:///C:/ATOS_Projekty/ZDD/web-ui/app/, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/_index.js, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nuxt/, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules/_index.js,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nuxt/node_modules, file:///C:/ATOS_Projekty/ZDD/web-
ui/app/node_modules/nitropack/, file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules/_index.js,
file:///C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/node_modules
at resolvePath (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/mlly/dist/index.mjs:1079:10)
at _resolve (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/dist/shared/nitro.8d0213e3.mjs:304:22)
at Object.resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/nitropack/dist/shared/nitro.8d0213e3.mjs:348:34)
at async resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/rollup/dist/es/shared/rollup.js:21737:26)
at async ModuleLoader.resolveId (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/rollup/dist/es/shared/rollup.js:22037:19)
at async /C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:773:14
at async Promise.all (index 0)
at async /C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:765:30
at async rewriteRequireExpressionsAndGetImportBlock (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:1312:28)
at async transformCommonjs (/C:/ATOS_Projekty/ZDD/web-ui/app/node_modules/#rollup/plugin-commonjs/dist/es/index.js:1874:23)`
devextreme-vue/menu is importing from devextreme/ui/menu, but it looks like this module is not being passed through during build.
Do I have to declare the dependency somewhere in my code to notify build server to use it? I have tried various things already (like trying to convince Vite (rollup) not to perform tree shaking or to switch to Webpack instead), but always ending up with the same result. But maybe I just fail to do it correctly, I still have to learn a lot about how exactly the things work here. Any help/clues will be appreciated.
This is my package.json in case I shall change or install something there.
{
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare",
"start": "nuxt start"
},
"devDependencies": {
"nuxt": "3.0.0-rc.8"
},
"dependencies": {
"devextreme": "22.1.4",
"devextreme-vue": "22.1.4"
}
}
EDIT: my node is 16.17.0 and npm 8.19.0, maybe the versions are relevant...
So the working solutuion appears to be adding a plugin, in my case named dx.client.ts, but it shouldn't matter, into /plugins folder which imports all necessary components and makes them globally available inside the application:
import { DxButton } from "devextreme-vue/button";
import { DxMenu, DxItem } from 'devextreme-vue/menu';
// the list goes on as the app grows
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp
.component("DxButton", DxButton)
.component("DxMenu", DxMenu)
.component("DxItem", DxItem);
// the list goes on as the app grows
});
I also had to add:
ssr: false
option into nuxt.config.ts, otherwise I ended up with Entry module cannot be external (devextreme-vue). error message during build.
So it has some limitations, but so far it works.
EDIT: it turned out, that while it works fine for some DevExtreme components without further adjustments, some components (like DxForm) also require to disable tree-shaking during Vite build - see how to do it. Otherwise the necessary files are lost in the build process and vague runtime error TypeError: f(...)[t] is not a function appears while rendering the component.
Thanks Stefan (stenet) for the right answer provided here

Jest command not recognized

So i just started learning about Test Driven Developement and as an example i was asked to run the command npm test helloWorld.spec.js in the terminal but i got this error :
> javascript-exercises#1.0.0 test
> jest "helloWorld.spec.js"
'jest' n’est pas reconnu en tant que commande interne
ou externe, un programme exécutable ou un fichier de commandes.
// in english jest isn't recognized as an internal command or external
I'm working on windows and the only thing i have installed is node so what do i have to do?
Choose one of the following methods
1) Install globally
You need to install jest globally:
npm install jest -g
Note: You will have to call it as jest something.spec.js in your cli or specify a test command in your package.json.
2) Install locally
Install jest locally with npm install jest -D.
You can use a script in your package.json called test which would be "test": "jest".
If any of the above don't work, try reinstalling jest.
If it still doesn't work, try removing node_modules and npm cache clean --force and npm install
3) Config file
If you already have jest installed but it's not working, you can use a config file to track files based on regex pattern (you can do a lot more if you check out the docs).
The following part is from the docs:
Jest's configuration can be defined in the package.json file of your project, or through a jest.config.js, or jest.config.ts file or through the --config <path/to/file.js|ts|cjs|mjs|json> option. If you'd like to use your package.json to store Jest's config, the "jest" key should be used on the top level so Jest will know how to find your settings:
{
"name": "my-project",
"jest": {
"verbose": true
}
}
Or through JavaScript:
// Sync object
/** #type {import('#jest/types').Config.InitialOptions} */
const config = {
verbose: true,
};
module.exports = config;
// Or async function
module.exports = async () => {
return {
verbose: true,
};
};
Or through TypeScript (if ts-node is installed):
import type {Config} from '#jest/types';
// Sync object
const config: Config.InitialOptions = {
verbose: true,
};
export default config;
// Or async function
export default async (): Promise<Config.InitialOptions> => {
return {
verbose: true,
};
};
When using the --config option, the JSON file must not contain a "jest" key:
{
"bail": 1,
"verbose": true
}
Regex options
testMatch [array]
(default: [ "**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)" ])
The glob patterns Jest uses to detect test files. By default it looks for .js, .jsx, .ts and .tsx files inside of __tests__ folders, as well as any files with a suffix of .test or .spec (e.g. Component.test.js or Component.spec.js). It will also find files called test.js or spec.js.
Note: Each glob pattern is applied in the order they are specified in the config. (For example ["!**/__fixtures__/**", "**/__tests__/**/*.js"] will not exclude __fixtures__ because the negation is overwritten with the second pattern. In order to make the negated glob work in this example it has to come after **/__tests__/**/*.js.)
testRegex [string | array]
Default: (/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$
The pattern or patterns Jest uses to detect test files. By default it looks for .js, .jsx, .ts and .tsx files inside of \_\_tests\_\_ folders, as well as any files with a suffix of .test or .spec (e.g. Component.test.js or Component.spec.js). It will also find files called test.js or spec.js. See also testMatch [array], but note that you cannot specify both options.

Migrating from Babel to SWC with React

TL;DR
How to translate a node script like this:
"test": "NODE_ENV=test riteway -r #babel/register 'src/**/*.test.js' | tap-nirvana",
to use SWC instead of Babel?
Context
We recently upgraded our Next.js version. Next.js now supports SWC instead of Babel.
The unit tests for React in our project are written with RITEway. The test command is:
"test": "NODE_ENV=test riteway -r #babel/register 'src/**/*.test.js' | tap-nirvana",
It transforms the files with Babel first because otherwise import statements and JSX would cause errors.
During our attempts to migrating to SWC, we had no luck with the CLI. However, we found the #swc-node/register package. It allowed us to transform our command like this:
"test": "riteway -r #swc-node/register src/**/*.test.js | tap-nirvana"
which fixes new syntax like the import statement and a test like this would run:
import { describe } from 'riteway';
describe('my test', async assert => {
assert({
given: 'true',
should: 'be true',
actual: true,
expected: true,
});
});
However, tests for React components like this
import { describe } from 'riteway';
import render from 'riteway/render-component';
import Authentication from './user-authentication-component';
describe('user authentication component', async assert => {
const $ = render(<Authentication />);
assert({
given: 'just rendering',
should: "render 'Authentication'",
actual: $('*:contains("Authentication")').text(),
expected: 'Authentication',
});
});
still throw the following error:
$ yarn test
yarn run v1.22.17
$ riteway -r #swc-node/register src/**/*.test.js | tap-nirvana
/Users/user/dev/learning-flow/node_modules/#swc/core/index.js:135
return bindings.transformSync(isModule ? JSON.stringify(src) : src, isModule, toBuffer(newOptions));
^
Error: error: Expression expected
|
7 | const $ = render(<Authentication />);
| ^
error: Expression expected
|
7 | const $ = render(<Authentication />);
| ^
error: Unexpected token `)`. Expected this, import, async, function, [ for array literal, { for object literal, # for decorator, function, class, null, true, false, number, bigint, string, regexp, ` for template literal, (, or an identifier
|
7 | const $ = render(<Authentication />);
| ^
Caused by:
0: failed to process js file
1: Syntax Error
at Compiler.transformSync
How can we create that command so that it runs with SWC?
After some experimentation I found out that it works if you import React from 'react'; in every file (both the component as well as the test) and change the file extensions to .jsx as described in the docs.
However, this is unsatisfying, as we'd like to use React 17's JSX transform feature to avoid having to import React in every file. Additionally, we'd like to keep all file endings .js.
We tried setting .swcrc without any luck so far.
I'm posting this answer here in case no way to configure .swcrc can be found.
I'll assume your question is only about jest and not about the webpack setup for swc.
I've never used swc myself in jest so this is just a shot in the dark, but I found a package for jest called #swc-node/jest which allows you to use a transformer like:
module.exports = {
transform: {
'^.+\\.(t|j)sx?$': ['#swc-node/jest'],
},
}
Which should allow you to transpile all [jt]sx? imports.
There's also a different one called #swc/jest which seems to do the same thing.
I'd start with trying those.
Your issue is that jest isn't able to parse your code, for example if you were using typescript you'd need something like ts-jest in order to parse your TS for you, I think in this case you need a swc/jest transpiler which should first compile your code and output it to memory, then funnel it to jest to run it.
The alternative is that you could compile the tests before hand using swc, then run jest on the compiled files as a separate step. At least with TS you can do that, first compile everything using tsc and then run jest on the .js output. I'm sure swc should work the same.
As to why the #swc-node/register package you're using isn't working, I have no idea.

Fail Gatsby build if environment variable missing

I have experimented with adding environment variables to my Gatsby project using .env.development and .env.production files and it's working great.
I would like to have my builds fail if one of the environment variables is missing, however I can't seem to see how to enable this functionality.
I have read through the Gatsby environment variables documentation, but can't seem to see how this would work? is this possible?
I believe it uses dotenv/webpack define plugin under the hood.
I’m sure there are other ways to do this, but with some quick tests, this approach seems to be working well for me.
In your gatsby-config.js file, you can choose to explicitly require the dotenv, so you can use those environment variables in your config.
I added the following, and now the Gatsby build will fail unless the specified environment variables are present.
// Load the environment variables, per
// https://www.gatsbyjs.org/docs/environment-variables/#server-side-nodejs
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
})
function checkEnv(envName) {
if (typeof process.env[envName] === 'undefined' || process.env[envName] === '') {
throw `Missing required environment variables: ${envName}`
}
}
try {
checkEnv('NODE_ENV')
checkEnv('EXAMPLE_MISSING_ENV')
checkEnv('EXAMPLE_API_KEY')
} catch (e) {
throw new Error(e)
}
// The rest of the config file
I could imagine customizing this further, ex. logging a warning for a variable with a fallback versus throwing an error for one that is required by your content sourcing plugin or theme. Hope this is helpful as a starting point!
I couldn't find built-in solution for this on Gatsby neither. You may do it manually, but still not too easy.
First problem: If you wanna load your environment from file while running npm script; it can not be loaded right away. But you may trigger a script file, and it can load this environment variables before your check.
lets say build.sh on root directory of project :
source ./.env.development # this line will set env variables
if [ "$API_KEY" = 927349872349798 ] ; then
npm run build
fi
Another problem rises; some developers might want to run it on windows maybe. So better use famous cross-env package.
npm i cross-env
Then everything is ready, add your secure-build :
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1",
"secure-build": "cross-env-shell \"./build.sh\""
},
And run it :
npm run secure-build
This solution looks too much for me as we created a build.sh and install a new package. Maybe there is cleaner solution. I am not Gatsby Guru after all.
I added env checking to the onPreInit life cycle hook in gatsby-node.ts:
const envVariablesList = [
"ENV1",
"ENV2",
"ENV3",
];
function envVarChecker(vars: string[]): string | undefined {
return vars.find(
(item) => process.env[item] === undefined || process.env[item] === ""
);
}
export const onPreInit: GatsbyNode["onPreInit"] = ({ actions }) => {
const emptyEnv = envVarChecker(envVariablesList);
if (emptyEnv !== undefined) {
throw new Error(`Env variable: ${emptyEnv} is empty!`);
}
};
It fails build almost at the very beginning (during pre-bootstrap phase) if any of the declared variables is missing

Property '' does not exist on type 'Request<ParamsDictionary>'

When trying to extend the Request interface from the package express to add some custom properties, I'm getting the following typescript error:
TS2339: Property '' does not exist on type 'Request<ParamsDictionary>'.
Do you know how to solve that?
Since a recent update of its typings and dependencies, I found that the following should fix the errors in your application.
In your tsconfig.json
{
"compilerOptions": {
//...
"typeRoots": [
"./custom_typings",
"./node_modules/#types"
],
}
// ...
}
And in your custom typings
// custom_typings/express/index.d.ts
declare namespace Express {
interface Request {
customProperties: string[];
}
}
Just add the following, what this does is it simply adds a custom property to the express Request interface
declare global {
namespace Express {
interface Request {
propertyName: string; //or can be anythin
}
}
}
I recently had the same issue, I followed the solution in the previous comments and this repo and I still had the same issue. After doing more digging it seems like it's a bug with ts-node.
To solve this you need to run your server with a --files flag
So if you normally run your server
ts-node ./src/server.ts or nodemon ./src/server.ts
Change it to
ts-node --files ./src/server.ts or nodemon --files ./src/server.ts
After that, I was able to get rid of both the VScode errors and errors while starting the server.
In my case it was missing types for express. What I'm currently working on is migrating our codebase from Yarn to PNPM. The difference with PNPM is it doesn't hoist dependencies the way Yarn does so I had to add the dependencies on the package.json for each workspace that would use that dependency.
This is the error I encountered:
TSError: ⨯ Unable to compile TypeScript:
../server/src/api/filters/googleFilter.ts:6:23 - error TS2339: Property 'headers' does not exist on type 'Request<core.ParamsDictionary>'.
6 const idToken = req.headers.authorization;
It took me quite a few searches to look for a fix when I decided to open up the node_modules folder of that workspace. Inside node_modules/#types/express/index.d.ts
/// <reference types="express-serve-static-core" />
/// <reference types="serve-static" />
import * as bodyParser from "body-parser";
import serveStatic = require("serve-static");
import * as core from "express-serve-static-core";
import * as qs from "qs";
I saw my IDE showing errors telling me that it cannot find the types for express-serve-static-core and serve-static so what I did was to add it on the package.json of that workspace and that fixed the errors on the terminal.
Hope this helps someone else who will encounter the same issue with PNPM.
This worked for me!
Using ts-node
Add the following file to add a property to the express Request interface as suggested by #Rishav Sinha
Add this file src/types/types.custom.d.ts
declare global {
declare namespace Express {
interface Request {
user?: any,
page?: number,
}
}
}
// If this file has no import/export statements (i.e. is a script)
// convert it into a module by adding an empty export statement.
export { }
Add in tsconfig.json
{
"compilerOptions": {
//...
"typeRoots": [
"./types",
"./node_modules/#types"
],
}
// ...
}
Run this command with --files options as suggested by #Shahar Sharron
If you installed globally ts-node
$ ts-node --files ./src/index.ts
or to run from your project dependencies ts-node
$ npx ts-node --files ./src/index.ts
Using nodemon
If you want to use nodemom
Add this file in folder project nodemon.json
{
"watch": ["src/**/*.ts"],
"ext": "ts,json",
"ignore": [
"src/**/*.spec.ts",
"src/**/*.test.ts"
],
"exec": "npx ts-node --files ./src/index.ts"
}
Run nodemon
$ nodemon

Categories

Resources