Trying to unit test reactjs application using mocha but getting error from es6 features (import/export) used inside node_modules folder. The application in question is transpiled using babel but since one of react component is using a module from node_modules its throwing error Syntax Error:Unexpected token export. I am aware that babel ignores node_modules folder by default, but not sure how to approach this. Any help would be appreciated. Thanks.
Test Command :-
"test": "SET NODE_ENV=test&& mocha --require #babel/register --require ignore-styles -r jsdom-global/register \"./src/**/*.test.js\"",
babel.config.js :-
module.exports = function (api) {
const presets = ["react-app"];
const plugins = [
"#babel/plugin-transform-modules-commonjs",
"inline-react-svg"
];
const ignore = [/node_modules/]
api.cache(false);
return {
presets,
plugins,
ignore
}
};
Got it working!. Had to switch from Mocha to Jest since I was using react-app-rewired which was internally configured to use Jest. A small change in config-override.js was needed. Added a jest config with "transformIgnorePatterns": ["node_modules/(?!MODULES_TO_BE_TRANSPILED)"]. Hope it helps others.
try this command, you need to pass ignored directories in command line with --ignored option.
./node_modules/.bin/babel . -d ~/app_compressed/ --ignore node_modules,test,assets,stuff,views,public,test,spec,logs,lib/jasmine_examples,db,routes/api/drafts,**/drafts
Also, make sure to use a babel.config.js file instead of a .babelrc file.
so the config file will look like following.
module.exports = function (api) {
api.cache(true);
return {
babelrcRoots: [
'.',
'./modules/*'
],
ignore: [/node_modules/],
presets: ["#babel/preset-env"]
};
}
Related
I have a mature CRA-based React app running with Webpack 5. I would like to have a separate project (in git, etc) where Storybook lives and points to the components in the app. (The app has tons of devs in and out of it, and dropping a bunch of Storybook packages in there, as well as introducing legacy-peer-dependencies thanks to webpack 5, would be quite frowned upon).
I also want devs to have a good experience being able to use Storybook to write components, so I want Storybook to see the current code of the project components, not some exported package. And same as above, there are many devs and a lot of inertia, so moving components to a separate standalone library is not an option.
My ideal for local development:
components and stories: /MyProject-App/src/Components/...
storybook app. : /MyProject-Storybook/stories/...
(Production I'm not worried about yet)
Installing Storybook inside the app works fine (as long as you run with --legacy-peer-deps). I am using the npx storybook init script and it works fine. But if I try to run Storybook out of a separate directory and target the app directory's Components, it breaks. If I run Storybook out of the app, and point it to stories/components outside that repo (which I copied and pasted just as a debugging measure), it breaks. Going up and out of the current project root breaks.
To do this, I am trying to point stories in /MyProject-Storybook/.storybook/main.js to ../../MyProject-App/src/Components.... When I do this and npm run storybook, I get the error output:
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/#storybook/source-loader/dist/cjs/index.js
**You may need an additional loader to handle the result of these loaders.**
The error is always on some basic ES6 syntax, arrow functions etc. If I run the same Storybook install out of MyProject-App (same version numbers / same main.js just pointed at the local path instead of the ../other path) it works.
In addition to this, I tried it the other way - running storybook out of the App folder (where I know it runs), and only changing the main.js stories directory to an outside-that-repo folder where I copied my Components and stories into. It breaks in the same way - I get the same You may need an additional loader to handle the result of these loaders. message, with it pointing to any example of ES6 syntax as an 'error'.
I found this similar question - Storybook can't process TS files outside of the project
recommending to look into Storybook's webpack loaders - https://storybook.js.org/docs/react/builders/webpack
So I updated my .storybook/main.js to be the following:
module.exports = {
stories: [
'../../MyProject-Storybook/src/**/*.stories.mdx',
'../../MyProject-Storybook/src/**/*.stories.#(js|jsx|ts|tsx)'
],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'#storybook/addon-interactions',
'#storybook/preset-create-react-app'
],
framework: '#storybook/react',
core: {
builder: '#storybook/builder-webpack5'
},
webpackFinal: async (config, { configType }) => {
config.module.rules.push({
test: /\.(js|jsx)$/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
reportFiles: ['../**/src/**/*.{js,jsx}', '../../MyProject-Storybook/**.stories.{js,jsx}']
}
}
]
});
config.resolve.extensions.push('.js', 'jsx');
return config;
}
};
but to no avail - output from npm run storybook remains unchanged, an excerpt:
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
* ./node_modules/#storybook/source-loader/dist/cjs/index.js
You may need an additional loader to handle the result of these loaders.
| backgroundColor: { control: 'color' },
| },
> } as ComponentMeta<typeof Button>;
|
For an RN app.
I have a project structure like
root git repo
|-jest.config
|-package.json
|-screens/
|--git submodule
|--git submodule
|--.lintstagedrc
one repo at root with package.json and jest.config
and multiple git submodules in screens folder
Each submodule is a npm package which is symlinked in node modules and added in package.json pointing to the git branch.
Now what i wanted to do was add a precommit hook in each submodule and use the root configurations for jest to run when anything is committed in the submodule.
I am using husky and have defined a .lintstagedrc file in the screens folder which would be picked while running husky.
{
"./**/app/**/*.{js,jsx,ts,tsx}": [
"eslint --fix --ext .js,.jsx,.ts,.tsx --plugin tsc --rule 'tsc/config: [2, {configFile: \"../../../tsconfig.json\"}]'",
"jest --config ../../../jest.config.js --bail --forceExit --passWithNoTests --findRelatedTests"
]
}
i am trying to set the jest config using the args however when the commit hook runs it does not pick the config and gives a type error for RN polyfill files
Syntax Error node_modules/#react-native/polyfills/error-guard.js: Missing semicolon. (14:4)
> 14 | type ErrorHandler = (error: mixed, isFatal: boolean) => void;
The same runs correctly if the files are not part of submodule and directly in the root repo(while being at the same path)
when running npx jest --showConfig it is correctly showing the required jest config. but running jest always fails.
How do i get jest to pick the current config and assume the root folder for config is the root repo and not the submodule npm package as i suggest having a package.json defined in submodule might be causing issues
Or that given the submodule is symlinked to node_modules folder at root might be the issue.
Jest config(payments is an example submodule)
module.exports = {
// The preset is a node environment that mimics the environment of a React Native app. Because it doesn't load any DOM or browser APIs, it greatly improves Jest's startup time.
verbose: true,
preset: 'react-native',
// It helps you greatly improve the test speed.It does so by creating a cache of compiled modules so that it doesn't have to compile the node_modules every time we run tests.
cacheDirectory: './cache',
// Defines the files which we want to skip while generating coverage reports.
// coveragePathIgnorePatterns: ['./src'],
// Defines the threshold limit for all the tests to pass.If the coverage is less than the defined limit, the tests would fail.This helped us in keeping code coverage high throughout development.
coverageThreshold: {
global: {
// global thresholds
branches: 23,
functions: 25,
lines: 32,
statements: 32,
},
},
globals: {
'ts-jest': {
diagnostics: false,
},
},
collectCoverageFrom: [
'./src/**/*.js',
'./src/**/*.ts',
'./src/**/*.tsx',
'!**/node_modules/**',
'!**/vendor/**',
],
testPathIgnorePatterns: ['src/.+((?:.ignored)|(?:mock)).(ts|js)x?'],
transform: {
'^.+\\.(ts|tsx|js|jsx)$': 'babel-jest',
},
// All the npm modules which need to be transpiled are added here.These modules are basically ES6/ 7 modules.
transformIgnorePatterns: [
'/node_modules/(?!(jest-)?#?react-native|payments|react-clone-referenced-element|react-navigation|#react-native-community|rn-range-slider|victory|react-native-svg|recoil)',
],
setupFilesAfterEnv: [
'<rootDir>/src/tests/setupTests.js',
'<rootDir>/node_modules/react-native-gesture-handler/jestSetup.js',
'#testing-library/jest-native/extend-expect',
],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
moduleNameMapper: {
'\\.svg': '<rootDir>/src/tests/mocks/svgMock.js',
'^src/(.*)': '<rootDir>/src/$1',
'^config/(.*)': '<rootDir>/config/$1',
'^app/(.*)': '<rootDir>/app/$1',
'^setup/(.*)': '<rootDir>/setup/$1',
'^payments/(.*)': '<rootDir>/src/screens/payments/$1',
},
notify: true,
notifyMode: 'always',
};
Is it possible to set environment variables in the manifest.json file of a Chrome Extension?
Like wOxxOm said, I used webpack to proccess manifest.json.
In my case, I needed to set version automatically on manifest file.
I added to webpack script:
plugins: [
new CopyWebpackPlugin([
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modify(content)
}
}
]),
]
And the modify function replaces version on file for the parameter:
function modify(buffer) {
var manifest = JSON.parse(buffer.toString());
let argv = process.argv[2];
if (argv) manifest.version = argv.split("=")[1];
let manifest_JSON = JSON.stringify(manifest, null, 2);
return manifest_JSON;
}
So, I build like "yarn build --version=x.x" and webpack do what I need.
PS: if you're going to use this, remember to change:
the manifest.json directory, if necessary;
the value in the modify function, in my case it was version
As the OP has mentioned in her answer, using the copy-webpack-plugin in the webpack.config.js file is the way to go if you're building your Chrome Extension with React. However, if your React app is based on create-react-app, directly editing the webpack.config.js file (which is located in node_modules/react-scripts/config) is not recommended.
In such a case, use craco, which is an npm package that can be used to customize an app based on create-react-app. Here's how you do it:
Install craco into your project using npm i #craco/craco.
Install copy-webpack-plugin as a dev-dependency in your project using npm i --save-dev copy-webpack-plugin.
Let's suppose we're creating a development and a production build of our Chrome Extension. Let's also suppose we've already assigned "version": "0.1.0" in our Chrome Extension's manifest.json. Depending on the build type, we'd like to assign accordingly the version_name field in our Chrome Extension's manifest.json, e.g., "version_name": "0.1.0 dev" for development and "version_name": "0.1.0" for production. In your React app's package.json, introduce two fields (the script names can be whatever you wish) as follows:
"scripts": {
...
"build-dev": "CRX_ENV=dev craco build", // or "set CRX_ENV=dev&& craco build" in the case of Windows
"build-prod": "CRX_ENV=prod craco build", // or "set CRX_ENV=prod&& craco build" in the case of Windows
...
}
Create a new file called craco.config.js in the root of your project. As per your need, do something similar to the following in the craco.config.js file:
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
webpack: {
plugins: [
new CopyPlugin({
patterns: [
{
from: "public/manifest.json",
to: "manifest.json",
transform(content, path) {
return modifyManifest(content)
},
},
],
}),
],
},
}
function modifyManifest(buffer) {
const manifest = JSON.parse(buffer.toString())
if (process.env.CRX_ENV === "dev") {
manifest.version_name = `${manifest.version} dev`
} else if (process.env.CRX_ENV === "prod") {
manifest.version_name = `${manifest.version}`
}
const manifestJson = JSON.stringify(manifest, null, 2)
return manifestJson
}
Run npm run build-dev. It will create a folder called build in your project root. This build folder is your unpacked Chrome Extension, which you can load into Chrome using the "Load unpacked" button on the chrome://extensions page. Once loaded, you should be able to see 0.1.0 dev as the version name of your Chrome Extension.
Delete the build folder created from the previous step and run npm run build-prod, and repeat the same steps. You should be able to see 0.1.0 as the version name of your Chrome Extension on the chrome://extensions page.
I am getting a syntax error in IE when this component of react is loaded in the webpage. Has anybody got the same problem? This is an inherited package, and a syntax error from node_modules makes no sense?
"use strict";
/* WEBPACK VAR INJECTION */(function(module) {
const colorConvert = __webpack_require__(/*! color-convert */ "./node_modules/color-convert/index.js");
const wrapAnsi16 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${code + offset}m`;
};
const wrapAnsi256 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${38 + offset};5;${code}m`;
};
If you are using newer versions of Node/NPM, check your package.json file -> "browserslist" section.
This is the default "browserslist" created for you if you do not have one defined:
In this case, if you run "npm start" on your LOCAL Environment, Babel will not create Polyfills for IE11 because its not included as a target browser in "development". To get this working, I deleted my node_modules directory completely, ran 'npm install', updated package.json with:
and ran 'npm start.
The reason why this fails is that babel or your other favorite transpiler might ignore node_modules (if that's how its configured), so you need to include it manually because IE does not support arrow function syntax.
First, if you search for wrapAnsi16 or wrapAnsi256 function names online it'll point you to common npm packages, such as: ansi-styles, chalk or color-convert, debug, strip-ansi, etc.
If you are using Webpack you can add the following to your rules:
module: {
rules: [{
exclude: /node_modules\/(?!(color-convert|ansi-styles|strip-ansi|ansi-regex|debug|react-dev-utils|chalk)\/).*/
}]
}
or, easier to read:
module: {
rules: [{
include: [
path.resolve(__dirname, 'node_modules/ansi-styles'),
path.resolve(__dirname, 'node_modules/strip-ansi'),
... other's here...
path.resolve(__dirname, 'src'),
]
}]
}
Hope this helps somebody in the future ;)
TLDR; you don't need this library, just run
npm run build
And it will be excluded from your build.
I have same problem with create-react-app, and I solve it (no). From my discovery, this library should not appear in browser, because it was designed for nodejs environment. Also I found, this library come to me as dependency of jest, and jest is dependency for tests and it come as dependency for react.
So, I run
npm run build
server -s build
And try my application in IE. And it work. So, when you run
npm start
It make file including dev dependencies and other garbage that should not appear in production and in browser at all. When you run
npm run build
It make file only with required project libraries.
I had similar issue #punkbit solution and installing 'react-app-polyfill'
and importing it at the top of the index.js file solved it
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
If it still does not work delete node-modules and reinstall also clear cache in IE.
All the best :)
This problem occurs because your compiled code contains (modern) ES6 syntax whilst IE11 only supports ES5.
A way to fix this is to instruct webpack to specifically compile the mentioned packages into ES5;
module: {
rules: [{
test: /\.(tsx?|js)$/,
include: [
// These dependencies have es6 syntax which ie11 doesn't like.
// Whenever you see a "SyntaxError" that crashes IE11 because of a new lib, add it here.
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/pkce-challenge'),
path.join(__dirname, 'node_modules/fuse.js')
],
use: [{
loader: 'ts-loader', // Or whatever loader you're using
}]
}]
}
for me this was: fuse.js, pkce-challenge and react-intl.
I'm writing a web app in TypeScript. The app uses React and Relay from Facebook.
My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel. In order for Relay to work in the browser, a Babel plugin needs to transform the Relay GraphQL queries: https://facebook.github.io/relay/docs/guides-babel-plugin.html. The problem is, because TSC first transpiles these queries, the Babel Relay plugin doesn't recognize them anymore so they don't get transpiled into something the browser understands, so the browser throws an error:
Uncaught Invariant Violation: RelayQL: Unexpected invocation at
runtime. Either the Babel transform was not set up, or it failed to
identify this call site. Make sure it is being used verbatim as
Relay.QL.
My TypeScript source code:
const SiteQuery = {
store: () => Relay.QL`query { site }`
};
... this gets compiled by TSC into something like this:
var SiteQuery = {\r\n store: function () { return (_a = [\"query { site }\"], _a.raw = [\"query { site }\"], Relay.QL(_a)); var _a; }\r\n};
... instead of something like this (because the Babel Relay plugin doesn't do its work properly):
var SiteQuery = {\n store: function store() {\n return (function () {\n return {\n fieldName: 'site',\n kind: 'Query',\n metadata: {},\n name: 'Router',\n type: 'Site'\n };
This is because the Babel Relay plugin doesn't recognize the transpiled version, and as a result it doesn't transpile the query into something the browser understands.
How to make this work?
The answers here were helpful, but I thought I'd share what finally worked for me.
Setup your babel-relay-plugin correctly. If you're running into problems here, I recommend using the npm package babel-relay-plugin-loader which then allows you to specify the location of your schema.json in package.json. For example:
{ "metadata": { "graphql": { "schema": "./schema.json" } } }
Setup your babel config correctly. It should look something like this:
{
"passPerPreset": true,
"presets": [
"react",
"es2015",
"stage-0"
],
"plugins": [
"babel-relay-plugin-loader"
]
}
},
Setup your tsconfig to target "es6" -- this actually was essential to make my setup work. ts-loader then compiles to es6 and Babel handles the transpile down to es5.
Finally, add the loaders to your webpack config. Remember, it applies these RIGHT to left. So, mine looks like this:
loaders: [
{
test: /.tsx?$/,
exclude: /node_modules/,
loader: 'react-hot!babel!ts-loader',
},
],
You need to tell the Typescript compiler to transpile to ES6, then use Babel with babel-relay-plugin and es2015 preset to transpile the code to ES5 to run in your browser.
I recommend using Webpack to orchestrate all this. These will get you started:
http://www.jbrantly.com/typescript-and-webpack/
http://www.jbrantly.com/es6-modules-with-typescript-and-webpack/
The posts were written for Babel 5.x, so you'll need to manually add es2015 preset to make sure Babel compiles the ES6 sources to ES6.
Just in case, when you say
My TypeScript source code gets compiled into ES6 code using the TypeScript compiler TSC. Then, the ES6 code gets transpiled into ES5 code using Babel.
You can instruct TypeScript itself to transpile directly to es5, just set target: 'es5' in tsconfig.json and that's it, hope it helps since you can eliminate babel from your compile chain.