How to setup the Pug for Next.js? - reactjs

Almost no search results for "nextjs pug". Google suggests the results for "nuxtjs pug" which is the completely different framework.
One of two relevant search results is this issue. The suggested minimal setup requires too much plugins (I can't understand why I need each of them), too complicated cofigurations and does not work with current versions.
package.json
"#babel/core": "^7.0.0-beta.51",
"#babel/plugin-transform-react-jsx": "^7.0.0-beta.51",
"#babel/plugin-transform-runtime": "^7.0.0-beta.51",
"#babel/preset-env": "^7.0.0-beta.51",
"#babel/runtime": "^7.0.0-beta.51",
"babel-core": "7.0.0-bridge.0",
"babel-plugin-transform-react-pug": "git://github.com/shirohana/babel-plugin-transform-react-pug.git#dist"
} } ```
**.babelrc.js**
```javascript module.exports = function (api) { api.env() return {
presets: [
['#babel/env', { useBuiltIns: 'entry' }]
],
plugins: [
['babel-plugin-transform-react-pug'],
['#babel/plugin-transform-react-jsx'],
['#babel/plugin-transform-runtime']
] } } ```
https://github.com/pugjs/babel-plugin-transform-react-pug/pull/48#issuecomment-406466928
Other relevant search result is Is it possible to use Framer Motion in React with pug question. I tried below solution:
{
"presets": ["next/babel"],
"plugins": [
"transform-react-pug",
[
"transform-jsx-classname-components"
],
"transform-react-jsx"
]
}
It's very interesting, but sometimes in works, sometimes - no.
I tried to create two projects. Firstly it works in both projects but then broke with error:
ReferenceError: React is not defined
at HomePage (C:\Users\****\Build\InteractiveImplementation\server\pages\index.js:63:3)
at processChild (C:\Users\****\node_modules\react-dom\cjs\react-dom-server.node.development.js:3353:14)
at resolve (C:\Users\****\node_modules\react-dom\cjs\react-dom-server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (C:\Users\****\node_modules\react-dom\cjs\react-dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (C:\Users\****\node_modules\react-dom\cjs\react-dom-server.node.development.js:3690:29)
at renderToString (C:\Users\****\node_modules\react-dom\cjs\react-dom-server.node.development.js:4298:27)
at Object.renderPage (C:\Users\****\node_modules\next\dist\next-server\server\render.js:53:854)
at Function.getInitialProps (C:\Users\****\Build\InteractiveImplementation\server\pages\_document.js:556:19)
at loadGetInitialProps (C:\Users\****\node_modules\next\dist\next-server\lib\utils.js:5:101)
at renderToHTML (C:\Users\****\node_modules\next\dist\next-server\server\render.js:53:1145)
This error will leave even don't use the Pug:
import React, { ReactNode } from "react";
class TestComponent extends React.Component<TestComponent.Properties,TestComponent.State> {
public state: TestComponent.State = {
count: 0
}
public render(): ReactNode {
// return pug`
// main
// div ${this.props.message}
// div props.message
// `;
return (
<div onClick={() => this.increment(1)}>
{this.props.message} {this.state.count}
</div>
)
}
private increment(amt: number): void {
this.setState((state: TestComponent.State): TestComponent.State => ({
count: state.count + amt,
}));
};
}
namespace TestComponent {
export type Properties = {
message: string;
}
export type State = {
count: number;
};
}
export default TestComponent;
You may want to know what I did directly before application broken.
Well, I had not record each my of actions, but I had not make some big changes like directories renamig or configuration editing directly before first failed launch. Anyway, we need know where config is wrong and how to fix it.

Try to import this in your pages/index.tsx
import React from "react";
For Babel transpilation of any jsx code, react import is needed. Import react wherever you use jsx code snippets. This fixes your issue.

Related

Is there a way to oraginize imports in vs code without removing 'react import'

I am trying to organize imports on saving a file. So I updated vs code settings to always organize imports when saving a file.
But it also removes import React from 'react'.
So react gives me this error 'React' must be in scope when using JSX.
For eg,
import React from 'react'
const Temp = () => {
return (
<div>Temp</div>
)
}
export default Temp
organizes to
const Temp = () => {
return <div>Temp</div>;
};
export default Temp;
This is my react version - "react": "^16.13.1".
Have you tried using a babel.config.js file?
module.exports = {
presets: [
[
'#babel/preset-env',
{
modules: false,
},
],
['#babel/preset-react', { runtime: 'automatic' }],
],
};
I have a project that uses this and it works pretty fine.
Refer the docs for configuration.

React + Rollup - 'r is not defined'

Final edit: Thanks everyone for your help, however ultimately it was easier for me to transition to Webpack and Storybook. I'm leaving my original question untouched just in case it helps anyone in the future. Also, if anyone stumbles upon any issues configuring these (like I did), the link to the GitHub repo is below.
I'm creating a small lib using React and Rollup and trying to test locally with a CRA-powered project, however I'm facing this issue when importing a component from my library. I don't know if the problem is in my configuration or if this is a bug.
Uncaught ReferenceError: r is not defined
at Object.../dist/bundle.js (index.jsx:44)
Imported "Message" component where the error is happening
import React, { useEffect, useState } from 'react';
import { string, number, arrayOf } from 'prop-types';
import Container from './Container';
function Message({
text,
type,
timeout,
classes,
}) {
const [show, setShow] = useState(false);
useEffect(() => {
if (text && type) {
setShow(true);
setTimeout(() => setShow(false), timeout);
}
}, [text, type]);
const date = new Date();
return (
<Container
id={`message-${date}`}
key={`message-${date}`}
className={`${type}${classes?.map((className) => ` ${className}`)}`}
>
{
show
? (
<p>{text}</p>
) : ''
}
</Container>
);
}
// The source map points to this line when the error happens, but it still happens if I remove it and don't use prop-types, instead pointing to the closing bracket of the 'Message' function
Message.defaultProps = {
timeout: 3000,
classes: [],
};
Message.propTypes = {
text: string.isRequired,
type: string.isRequired,
timeout: number,
classes: arrayOf(string),
};
export default Message;
Test component where it's being used:
import React from 'react';
import { Message } from 'pure-ui';
import { getRandomArrayElement } from 'formatadores';
const types = [
'warning',
'error',
'success',
];
const texts = [
'This is a test',
'I will randomly display a message every so often, so stay sharp',
'Yet another test message',
];
const timeouts = [
5000,
3000,
1000,
];
function App() {
return (
<div>
<h1>Running...</h1>
<Message
type={getRandomArrayElement(types)}
text={getRandomArrayElement(texts)}
timeout={getRandomArrayElement(timeouts)}
/>
</div>
);
}
export default App;
rollup config file:
import babel from '#rollup/plugin-babel';
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import external from 'rollup-plugin-peer-deps-external';
import React from 'react';
import propTypes from 'prop-types';
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
export default [
{
input: 'src/index.js',
watch: true,
output: {
file: 'dist/bundle.js',
format: 'iife',
sourcemap: true,
globals: {
react: 'React',
'react-dom': 'ReactDOM',
'prop-types': 'PropTypes',
},
},
plugins: [
external(),
babel({
exclude: 'node_modules/**',
presets: [
'#babel/preset-env',
['#babel/preset-react', { runtime: 'automatic' }],
],
}),
resolve({ extensions }),
commonjs({
namedExports: {
react: Object.keys(React),
'react/jsx-runtime': ['jsx', 'jsxs', 'Fragment'],
'react/jsx-dev-runtime': ['jsx', 'jsxs', 'jsxDEV'],
'prop-types': Object.keys(propTypes),
},
}),
],
external: [
'react',
'react-dom',
'prop-types',
],
},
];
I tried changing the namedExports (and also removing them), linking React from the lib to use the same version from the CRA project (in the lib both React and React DOM are listed as peer dependencies), but I always end with the same result. Is there something wrong with my config? This is the first time I use Rollup for creating a React component lib, so maybe there's something I missed
If the above info is insufficient, here's the GitHub repo
Thanks in advance
Edit: I just saw that I forgot to import React in my test project, however after doing so the results were the same, editing my original question just to fix that.
Update 1: I changed several configurations (changed deprecated rollup-plugins to their currently maintained versions, added globals to the output part of rollup.config.js, added namedExports to commonjs plugin configuration, added an external section specifying react, react-dom and prop-types), but now what I'm getting is a React is not defined error, updating the question with the new config

IE11 React.memo + react-redux connect issue

I am trying to memoize redux-connected component using React.memo.
My code works normally in major browsers but IE throws error:
You must pass a component to the function returned by connect. Instead received {"$$typeof":60115,"compare":null}
Component code:
import React, { memo } from 'react';
import { connect } from 'react-redux';
const MyComponent = ({ some, prop }) => (
<div>Some React</div>
);
const MyComponentMemoized = memo(MyComponent);
const mapStateToProps = state => ({
some: someSelector(state),
prop: propSelector(state),
});
const MyComponentMemoizedAndConnected = connect(mapStateToProps)(MyComponentMemoized);
export default MyComponentMemoizedAndConnected;
Notes about app setup: using webpack with babel-loader, babel config:
"presets": [
[
"#babel/preset-env",
{
corejs: '3.6',
"targets": {
"chrome": "58",
"ie": "11"
},
useBuiltIns: 'usage',
},
],
"#babel/preset-react"
]
After hours of debugging I found this bug disappeared after I removed 'react-hot-loader/patch' from my webpack entry arr. Don't know why it happens, but hope it will save someones time
If anyone run into this issue, check the order you are using memo and connect.
For example, using compose from recompose:
compose(
React.memo,
connect(mapStateToProps),
)(MyComponent);
React.memo should be used before connect.

Warning: Prop `className` did not match. when using styled components with semantic-ui-react

I use this code to margin my Button from top:
const makeTopMargin = (elem) => {
return styled(elem)`
&& {
margin-top: 1em !important;
}
`;
}
const MarginButton = makeTopMargin(Button);
and whenever i use MarginButton node, I get this error: Warning: PropclassNamedid not match. Server: "ui icon left labeled button sc-bwzfXH MjXOI" Client: "ui icon left labeled button sc-bdVaJa fKCkqX"
You can see this produced here.
What should I do?
This warning was fixed for me by adding an .babelrc file in the project main folder, with the following content:
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}
See following link for an example:
https://github.com/nblthree/nextjs-with-material-ui-and-styled-components/blob/master/.babelrc
Or you could just add this to your next.config.js. This also makes it so next-swc (speedy web compiler) works to reduce build times. See more here.
// next.config.js
module.exports = {
compiler: {
// Enables the styled-components SWC transform
styledComponents: true
}
}
You should install the babel plugin for styled-components and enable the plugin in your .babelrc
npm install --save-dev babel-plugin-styled-components
.babelrc
{
"plugins": [
[
"babel-plugin-styled-components"
]
]
}
The main reason I am posting this answer to help people understand the tradeoff. When we're using .babelrc in next project it's going to opt of SWC compiler which is based on Rust (Learn More).
It's going to show message something like this when you opt for custom bable config.
info - Disabled SWC as replacement for Babel because of custom Babel configuration ".babelrc"
I did more digging on this to only find out following! Ref
Next.js now uses Rust-based compiler SWC to compile
JavaScript/TypeScript. This new compiler is up to 17x faster than
Babel when compiling individual files and up to 5x faster Fast
Refresh.
So tradeoff was really huge, we can lose significant amout of performance. So I found a better solution which can solve this issue and keep SWC as default compiler.
You can add this experimental flag in your next.config.js to prevent this issue. Ref
// next.config.js
module.exports = {
compiler: {
// ssr and displayName are configured by default
styledComponents: true,
},
}
If you have already added babel plugins, delete the .next build folder & restart the server again
credit: Parth909 https://github.com/vercel/next.js/issues/7322#issuecomment-912415294
I was having the exact same issue and it was resolved by doing:
npm i babel-preset-next
npm install --save -D babel-plugin-styled-components
and adding this to .babelrc file:
{
"presets": ["next/babel"],
"plugins": [["styled-components", { "ssr": true }]]
}
Styled components server side rendering
Server Side Rendering styled-components supports concurrent server
side rendering, with stylesheet rehydration. The basic idea is that
everytime you render your app on the server, you can create a
ServerStyleSheet and add a provider to your React tree, that accepts
styles via a context API.
This doesn't interfere with global styles, such as keyframes or
createGlobalStyle and allows you to use styled-components with React
DOM's various SSR APIs.
import { renderToString } from 'react-dom/server'
import { ServerStyleSheet } from 'styled-components'
const sheet = new ServerStyleSheet()
try {
const html = renderToString(sheet.collectStyles(<YourApp />))
const styleTags = sheet.getStyleTags() // or sheet.getStyleElement();
} catch (error) {
// handle error
console.error(error)
} finally {
sheet.seal()
}
import { renderToString } from 'react-dom/server'
import { ServerStyleSheet, StyleSheetManager } from 'styled-components'
const sheet = new ServerStyleSheet()
try {
const html = renderToString(
<StyleSheetManager sheet={sheet.instance}>
<YourApp />
</StyleSheetManager>
)
const styleTags = sheet.getStyleTags() // or sheet.getStyleElement();
} catch (error) {
// handle error
console.error(error)
} finally {
sheet.seal()
}
In my case as im using nextjs
import Document, { Head, Main, NextScript } from "next/document";
import { ServerStyleSheet } from "styled-components";
export default class MyDocument extends Document {
static getInitialProps({ renderPage }) {
const sheet = new ServerStyleSheet();
const page = renderPage(App => props =>
sheet.collectStyles(<App {...props} />)
);
const styleTags = sheet.getStyleElement();
return { ...page, styleTags };
}
render() {
return (
<html>
<Head>{this.props.styleTags}</Head>
<body>
<Main />
<NextScript />
</body>
</html>
);
}
}
I have solved this issue following these steps.
Create a file named .babelrc in the root directory and configure the .babelrc file.
delete the .next build folder(It stores some caches).
Restart the server.
Hot reload the browser.
.babelrc configuration file
{
"presets": [
"next/babel"
],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}
PropType errors are runtime errors that will let you know that the data expected being passed to a prop is not what is expected. It looks like the className prop that is being set on your component is not the same when the component is rendered on the server and when it is then rendered in the client's DOM.
Since it looks like you are using server side rendering, you need to make sure that your class names are deterministic. That error is showing you the class that is being created by your styled-components library on the server and how it is different from the DOM. For libraries that do not normally have deterministic class names, you need to look at advanced configurations. Take a look at the styled-components documentation regarding specificity as it pertains to SSR.
//1. I got an error when using material-ui with Next.js
/********************************************* */
//2. The code I imported was like this :
const useStyles = makeStyles({
root: { // root must change
width: 100 ,
}
});
const Footer = () => {
const classes = useStyles();
return (
<div className={classes.root} > { /* root must change */}
<p> footer copyright #2021 </p>
</div>
)
}
export default Footer;
/********************************************* */
//3. I changed the code like this :
const useStyles = makeStyles({
footer: { // changed here to footer
width: "100%",
backgroundColor: "blue !important"
}
});
const Footer = () => {
const classes = useStyles();
return (
<div className={classes.footer} > { /* changed here to footer */}
<p> footer copyright #2021 </p>
</div>
)
}
export default Footer;
// I hope it works
For Old versions form Nextjs < 12, Go to next.config.js file and add this line inside nextConfig object:
experimental: {
// Enables the styled-components SWC transform
styledComponents: true
}
for new NextJs above 12:
compiler: {
styledComponents: true
}
if that does not work you need to make an NO SSR component wrapper like this:
// /components/NoSsr.js
import dynamic from 'next/dynamic'
const NoSsr = ({ children }) => <>{children}</>
export default dynamic(() => Promise.resolve(NoSsr), { ssr: false })
Then you need to add warp No SSR with your component like this:
// /pages/index.js
import NoSsr from '../components/NoSsr'
import CircleButton from '../components/buttons/CircleButton'
const HomePage = () => {
return (
<>
<p>Home Page Title</p>
<NoSsr>
{/* Here your styled-component */}
<makeTopMargin ele={...} />
</NoSsr>
</>
)
}
I'm using NextJS 12 and encountered the same issue, well error in the console, code was working ok.
I fixed it by creating a .babelrc file at the root of the project and add:
{
"presets": [
"next/babel"
],
"plugins": [
[
"styled-components",
{
"ssr": true,
"displayName": true,
"preprocess": false
}
]
]
}
Styled Components have full, core, non-experimental support in Next now (2022), but you have to turn them on:
Add the following to your next.config.js:
compiler: {
styledComponents: true,
},
My full, mostly vanilla, next.config.js now looks like this:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
compiler: {
// Enables the styled-components SWC transform
styledComponents: true,
},
}
module.exports = nextConfig
https://nextjs.org/blog/next-12-1#improved-swc-support
I followed all the other advice, around setting up .babelrc (or .babelrc.js), but noticed this message in the Next.js docs:
When css-in-js libraries are not set up for pre-rendering (SSR/SSG) it will often lead to a hydration mismatch. In general this means the application has to follow the Next.js example for the library. For example if pages/_document is missing and the Babel plugin is not added.
That linked to this file, showing that I needed to add this to pages/_document.tsx to:
// if you're using TypeScript use this snippet:
import React from "react";
import Document, {DocumentContext, DocumentInitialProps} from "next/document";
import {ServerStyleSheet} from "styled-components";
export default class MyDocument extends Document {
static async getInitialProps(
ctx: DocumentContext,
): Promise<DocumentInitialProps> {
const sheet = new ServerStyleSheet();
const originalRenderPage = ctx.renderPage;
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheet.collectStyles(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
};
} finally {
sheet.seal();
}
}
}
A blog post by Raúl Sánchez also mentions this solution, linking to the JavaScript version if you're not using TS (pages/_document.js):
// if you're *not* using TypeScript use this snippet:
import Document from 'next/document'
import { ServerStyleSheet } from 'styled-components'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const sheet = new ServerStyleSheet()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) =>
sheet.collectStyles(<App {...props} />),
})
const initialProps = await Document.getInitialProps(ctx)
return {
...initialProps,
styles: (
<>
{initialProps.styles}
{sheet.getStyleElement()}
</>
),
}
} finally {
sheet.seal()
}
}
}
If you are using create-react-app, you can use thi solution.
File called styled.ts
import styled from 'styled-components/macro';
import { css } from 'styled-components';
export const ListRow = styled.div`
...
...
`
Based on the files name, the prefix will be as following.
`${file_name}__{styled_component_name} ${unique_id}`
Meaning when implemented it will have the following classname
Although it would be nice to specify from where the first prefix would be taken from, meaning instead of file_name, we take folder_name. I currently dont know the solution for it.
To expand on C. Molindijk's answer, this error occurs when server-side class is different from client-side because styled-components generates its own unique class Id's. If your Next app is server-side rendered, then his answer is probably correct. However, Next.Js is by default statically generated, so unless you enabled SSR, configure it like this without ssr set to true:
{
"presets": ["next/babel"],
"plugins": [["styled-components"]]
}
This answer is for those who are using NextJs version > v12.0.1 and SWC compiler. You don't have to add _document.js file nor do babel related stuff anymore since it has been replaced by SWC compiler since v12.0.0. Only that your next.config.js file should look like the following since NextJs supports styled components after v12.1.0 and restart the server and it should work: more here
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
// add the following snippet
compiler: {
styledComponents: true,
},
};
module.exports = nextConfig;

Proper way to implement jwplayer in react component using webpack (react-starter-kit)

i am making VideoPlayer react component with jwpalyer and i am using webpack es6 for loading module
webpack support npm module loading & there is no npm for jwplayer
so am trying to include jwplayer.js using es6 import but it giving me error
ReferenceError: window is not defined
so any one can help me to properly setup jwplayer with webpack
import React, { PropTypes, Component } from 'react';
import $ from 'jquery';
import Player from "./lib/jwplayer/jwplayer.js";
import styles from './VideoPayer.css';
import withStyles from '../../decorators/withStyles';
import Link from '../Link';
#withStyles(styles)
class VideoPlayer extends Component {
static propTypes = {
className: PropTypes.string,
};
static defaultProps = {
file: '',
image: ''
};
constructor(props) {
super(props);
this.playerElement = document.getElementById('my-player');
}
componentDidMount() {
if(this.props.file) {
this.setupPlayer();
}
}
componentDidUpdate() {
if(this.props.file) {
this.setupPlayer();
}
}
componentWillUnmount() {
Player().remove(this.playerElement);
}
setupPlayer() {
if(Player(this.playerElement)) {
Player(this.playerElement).remove();
}
Player(this.playerElement).setup({
flashplayer: require('./lib/player/jwplayer.flash.swf'),
file: this.props.file,
image: this.props.image,
width: '100%',
height: '100%',
});
}
render() {
return (
<div>
<div id="my-player" className="video-player"></div>
</div>
)
}
}
export default VideoPlayer;
I think this is what you need to do:
Define window as external to the bundle so that references to it in other libraries are not mangled.
Expose a global variable jwplayer so that you can attach your key
(Optional) Create an alias to your jwplayer library
I've tested it and this configuration works for me, but only on the client and not on the server or isomorphically/universally.
webpack.config.js:
// Declare window as external
externals: {
'window': 'Window'
},
// Create an easy binding so we can just import or require 'jwplayer'
resolve: {
alias: {
'jwplayer':'../path/to/jwplayer.js'
}
},
// Expose jwplayer as a global variable so we can attach the key, etc.
module: {
loaders: [
{ test: /jwplayer.js$/, loader: 'expose?jwplayer' }
]
}
Then you can import jwplayer from 'jwplayer' and require('jwplayer').
Probably an old question but I recently found a relatively stable solution.
I include the jwplayer in a folder called app/thirdparty/jwplayer-7.7.4. Next, add it to the exclude in the babel loader so it is not parsed.
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /(node_modules|thirdparty)/,
}
I then use dynamic import in order to bootstrap my component and load jwplayer.
async function bootstrap(Component: React.Element<*>) {
const target = document.getElementById('root');
const { render } = await import('react-dom');
render(<Component />, target);
}
Promise.all([
import('app/components/Root'),
import('app/thirdparty/jwplayer-7.7.4/jwplayer.js'),
]).then(([ { default: Root } ]) => {
window.jwplayer.key = "<your key>";
bootstrap(Root);
});

Resources