I've got some horrendous code that has to be added to our project that you can see below. It basically checks if react-router exists in webpack and then tells our component what environment it is on.
let Link;
/* eslint-disable -- We have to use __non_webpack_require__ to handle the case when consumer has no react router (which is our external dependency) */
try {
// Link = __non_webpack_require__ && __non_webpack_require__('react-router/lib/Link');
if (__non_webpack_require__) {
Link = __non_webpack_require__('react-router/lib/Link'); // for Webpack
} else {
// Below line causes issue
Link = import('react-router/lib/Link').then(module => module); // for Rollup
}
} catch (e) { }
/* eslint-enable */
So how my project is setup is this is a repo that is a small part of a bigger one where react-router exists and we don't want to install react-router on our side as it causes other bugs. Because of this I get the below error when I go to build the bundle from rollup.
I've tried to ignore the dependency by using the skip property, the 'rollup-plugin-ignore' dependecy and also the externals property in webpack and none of these seem to work.
Examples:
skip: ['react-router/lib/Link'], // Default: []
externals: {
...nodeExternals(),
'react-router': 'react-router',
},
and following the example given here:
https://www.npmjs.com/package/rollup-plugin-ignore
Related
Swiper 8 and Jest (support ESM) Must use import to load ES Module
enter image description here
enter image description here
How we can solve if I need to keep swiper 8 (without downgrade)
In case someone runs into this same issue but is using NextJs 12.2, next/jest and Jest 28 the answer is a variation from Francisco Barros' answer.
// jest.config.js
const nextJest = require('next/jest')
const createJestConfig = nextJest({
// Path to Next.js app to load next.config.js
dir: './'
})
/** #type {import('#jest/types').Config.InitialOptions} */
const customJestConfig = {
/**
* Custom config goes here, I am not adding it to keep this example simple.
* See next/jest examples for more information.
*/
}
module.exports = async () => ({
/**
* Using ...(await createJestConfig(customJestConfig)()) to override transformIgnorePatterns
* provided byt next/jest.
*
* #link https://github.com/vercel/next.js/issues/36077#issuecomment-1096635363
*/
...(await createJestConfig(customJestConfig)()),
/**
* Swiper uses ECMAScript Modules (ESM) and Jest provides some experimental support for it
* but "node_modules" are not transpiled by next/jest yet.
*
* #link https://github.com/vercel/next.js/issues/36077#issuecomment-1096698456
* #link https://jestjs.io/docs/ecmascript-modules
*/
transformIgnorePatterns: [
'node_modules/(?!(swiper|ssr-window|dom7)/)',
]
})
The transformIgnorePatterns on jest.config.js prevents the Swiper files from being transformed by Jest but it affects the CSS files that are provided by this package.
Mocking these CSS files is the solution with the smallest configuration.
In my case, it didn't matter much about having access to these CSS files while testing but there are other approaches if these files are relevant to you.
// jest.setup.js
import "#testing-library/jest-dom/extend-expect";
jest.mock("swiper/css", jest.fn());
export {};
I created a repository for a full reference of the necessary setup.
https://github.com/markcnunes/with-jest-and-esm
Have in mind this setup might have to change for future Next.js / next/js versions but just sharing this approach in case this is useful for other people using this same setup.
I have the same issue and still searching for a solution; I believe what the OP is asking is how can we transform swiper/react into a CJS module on the JEST pipeline.
Since using ESM Experimental in jest is not a good option...
Downgrading to v6 is not an option;
Any code that imports Swiper v8 fails in JEST because Swiper 8 only exports ESM;
A few days have passed since my original response. In the mean time I have found a solution that I have been using to effectively use Swiper v8 while still being able to test components that depend on it using jest.
The trick is to map the ESM imports to actual JavaScript and CSS files exported by Swiper, which can then be processed by babel and transpiled into CJS.
Create a file
// ./mocks/misc/swiper.js
module.exports = {
// Rewrite Swiper ESM imports as paths (allows them to be transformed w/o errors)
moduleNameMapper: {
"swiper/react": "<rootDir>/node_modules/swiper/react/swiper-react.js",
"swiper/css": "<rootDir>/node_modules/swiper/swiper.min.css",
"swiper/css/bundle": "<rootDir>/node_modules/swiper/swiper-bundle.min.css",
"swiper/css/autoplay": "<rootDir>/node_modules/swiper/modules/autoplay/autoplay.min.css",
"swiper/css/free-mode": "<rootDir>/node_modules/swiper/modules/autoplay/free-mode.min.css",
"swiper/css/navigation": "<rootDir>/node_modules/swiper/modules/autoplay/navigation.min.css",
"swiper/css/pagination": "<rootDir>/node_modules/swiper/modules/autoplay/pagination.min.css"
},
// Allow Swiper js and css mapped modules to be imported in test files
transform: {
"^.+\\.(js|jsx|ts|tsx)$": ["babel-jest", { presets: ["next/babel"] }],
"^.+\\.(css)$": "<rootDir>/jest.transform.js"
},
// Do not transform any node_modules to CJS except for Swiper and Friends
transformIgnorePatterns: ["/node_modules/(?!swiper|swiper/react|ssr-window|dom7)"]
}
Create another file in the root of your repository
// jest.transform.js
"use strict"
const path = require("path")
// Requried to fix Swiper CSS imports during jest executions, it transforms imports into filenames
module.exports = {
process: (_src, filename) => `module.exports = ${JSON.stringify(path.basename(filename))};`
}
Finally in your jest configuration use the things you created
// jest.config.js
const swiperMocks = require("./mocks/misc/swipper");
module.exports = {
...yourConfigurations
moduleNameMapper: {
...yourOtherModuleNameMappers,
...swiperMocks.moduleNameMapper,
},
transform: {
...yourOtherTransforms
...swiperMocks.transform,
},
transformIgnorePatterns: [
...yourOtherTransformsIgnorePatterns
...swiperMocks.transformIgnorePatterns,
],
}
I'm trying to load #apollo/client on a React Native Expo app.
And I get this error:
While trying to resolve module #apollo/client from file /Users/andrepena/git/anglio-mobile-rn/screens/dictionary/index.tsx, the package /Users/andrepena/git/anglio-mobile-rn/node_modules/#apollo/client/package.json was successfully found. However, this package itself specifies a main module field that could not be resolved (/Users/andrepena/git/anglio-mobile-rn/node_modules/#apollo/client/main.cjs. Indeed, none of these files exist
Then I searched Stackoverflow and someone said I should add this to my metro.config.json
const { getDefaultConfig } = require("#expo/metro-config");
const defaultConfig = getDefaultConfig(__dirname);
defaultConfig.resolver.assetExts.push("cjs");
module.exports = defaultConfig;
But now, all imports from #apollo/client simply return undefined.
Example:
import { ApolloClient, InMemoryCache } from "#apollo/client";
console.log(ApolloClient); // undefined
console.log(InMemoryCache); // undefined
In fact, #apollo/client is exporting this object:
Object {
"default": 17,
}
Any suggestion?
This metro.config.js worked for me: (remember to install #expo/metro-config)
const { getDefaultConfig } = require('#expo/metro-config');
const config = getDefaultConfig(__dirname, {
// Initialize in exotic mode.
// If you want to preserve `react-native` resolver main field, and omit cjs support, then leave this undefined
// and skip setting the `EXPO_USE_EXOTIC` environment variable.
mode: 'exotic',
});
module.exports = config;
The exotic thing makes Metro to be able to find the weird cjs module that #apollo/client exports
I am using create-react-app (unejected) with this code:
class App extends Component {
state = {
path: 'some_string',
organization: null,
errors: null
}
componentDidMount() {
this.onFetchFromGitHub(this.state.path);
};
...
The code (the application) works as expected.
However I am getting an error in vscode:
Parsing error: unexpected token = eslint [134,9]
That is the "=" in:
state = {`
/|\
|
which is highlight in vscode.
My understanding is that I can use this format instead of a constructor with bindings.
As I said the app is working despite the error.
.eslintrc.yml
Which version of React are you using?
React introduced "hooks" in 16.8, and they largely replace the old "Component" class format.
See the introduction here: https://reactjs.org/docs/hooks-intro.html
Using hooks, your example above can be simplified to a function component:
const App = (props) => {
// This replaces the this.state/this.setState from a component
const [state, setState] = React.useState({
path: 'some_string',
organization: null,
errors: null
});
// This replaces the on mount
React.useEffect(() => {
onFetchFromGitHub(state.path);
}, []);
return ...
}
As for why your example does not work, I would suggest it is likely due to configuration of your IDE syntax highlighting. Check whether you have the right syntax plugins installed/active (es2015, react, etc.) and if your linter (if you have one) has the correct plugins and presets. Your code works fine in my IDE, with no errors.
I fixed this by installing eslint. This gave a problem due to conflict with create-react-app so I had to pin package.json version of eslint to 6.6.0 and then delete package-lock.json and remove node_modules/ and then I got about 30 warnings (instead of one).
Finally I changed the source code to fix the unnecessary parens and ignore propType errors and finally I am error free.
I'm writing unit tests for a client's website built with Gatsby. I need to be able to deliver 100% coverage. I am unable to make major edits to the source code, since I didn't build the site nor do I own the code, lest I risk breaking the UI (I'm not doing snapshot or UI testing).
I have been searching for an answer within Github issues, Stack Overflow, etc, and it seems there are recurring peculiarities with the usage of /* istanbul ignore next */.
With Gatsby, you have to check for references to the window for any scripts or Web APIs and conditionally ignore that code if typeof window === 'undefined', since Gatsby statically generates the site on the server. To add coverage to those statements, branches, functions and lines, I have been able to use /* istanbul ignore next */. However, I am having a rough time with a particular class component.
I have tried using /* istanbul ignore next */ before componentDidMount and componentDidUpdate, just inside the lifecycle definitions, between the function name and parentheses, before the if blocks within the lifecycles. I've also tried using /* istanbul ignore if */.
No matter what code I use, I cannot get coverage. I am open to any suggestions here, whether a better approach to using ignore statements or a hint on ways to create tests that would do the trick. Thank you for your help!
Here are uncoverable (thus far) lines of the component:
careers.js
componentDidMount() {
this.context.setHeaderTheme(`bright`)
/* istanbul ignore next */
if (typeof window !== `undefined` && typeof document !== `undefined`) {
if (!window.Grnhse) {
const script = document.createElement(`script`)
script.setAttribute(
`src`,
`<hidden/path/for/security/purposes>`
)
script.setAttribute(`width`, `100%`)
script.onload = () => window.Grnhse && window.Grnhse.Iframe.load()
document.body.appendChild(script)
} else {
if (window.Grnhse) {
window.Grnhse.Iframe.load()
}
}
}
}
componentDidUpdate() {
/* istanbul ignore next */
if (
!this.scrollDone &&
typeof window !== `undefined` &&
window.location.search.includes(`gh_jid`) &&
this.greenhouseContainer
) {
this.scrollDone = true
window.scrollTo({
top: this.greenhouseContainer.offsetTop,
behavior: `smooth`,
})
}
}
I think I found an answer that works.
Within jest.config.js with Jest version 26.0, you can configure the coverageProvider to be either babel (default) or v8 (considered experimental).
I changed to v8 and installed v8-to-istanbul:
npm i --save-dev v8-to-istanbul
This provides some new functionality which seems to work wonders. I got to 100% coverage on everything but functions immediately.
/* c8 ignore next 16 */
if (typeof window !== `undefined` && typeof document !== `undefined`) {
if (!window.Grnhse) {
const script = document.createElement(`script`)
script.setAttribute(
`src`,
`...`
)
script.setAttribute(`width`, `100%`)
script.onload = () => window.Grnhse && window.Grnhse.Iframe.load()
document.body.appendChild(script)
} else {
if (window.Grnhse) {
window.Grnhse.Iframe.load()
}
}
}
/* c8 ignore next 13 */
if (
!this.scrollDone &&
typeof window !== `undefined` &&
window.location.search.includes(`gh_jid`) &&
this.greenhouseContainer
) {
this.scrollDone = true
window.scrollTo({
top: this.greenhouseContainer.offsetTop,
behavior: `smooth`,
})
}
Please check out this package if you run into a similar issue: https://openbase.io/js/v8-to-istanbul/documentation#ignoring-the-next-line
Moreover, I found a method for testing that the script was appended to the DOM on componentDidMount with #testing-library/react and jest:
it(`adds script to body`, async () => {
render(<CareersWithProvider />)
const Grnhse = await waitFor(() => screen.findAllByTestId(`Grnhse`))
expect(Grnhse).not.toBeNull()
})
I'm trying to use react-loadable to implement code splitting, and as suggested in the docs I've created a HOC for it, like this:
export default function({ componentPath }) {
return Loadable({
loader: async () => {
const component = await import(componentPath)
return component;
},
delay: 200
});
}
and I use it like this
import withLoadable from "hoc/withLoadable";
....
const Home = withLoadable({componentPath: "containers/Home"});
but I got the following error
Error: Cannot find module 'containers/Home'
at eval (eval at ./src/hoc lazy recursive (main.chunk.js:formatted:98), <anonymous>:5:11)
Referring to the docs here, they mentioned this issue and how to solve it, I tried to add the modules, and webpack attributes but it didn't work.
BTW: in webpack.config.js I've added the "src" directory to the resolve modules like this:
...
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253
modules: ['src','node_modules'].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
...
I'm sure I miss something, but I can get it ...