TypeScript errors due to missing @types/react-dom and @types/webpack when using `
  • 31-May-2023
Lightrun Team
Author Lightrun Team
Share
TypeScript errors due to missing @types/react-dom and @types/webpack when using `

TypeScript errors due to missing @types/react-dom and @types/webpack when using `”strict”: true` and `”skipLibCheck”: false`

Lightrun Team
Lightrun Team
31-May-2023

Explanation of the problem

 

Bug Report:

When the tsconfig.json options "skipLibCheck": false and "strict": true are set, TypeScript errors occur due to missing dependencies @types/react-dom and @types/webpack. This issue is observed in a Next.js project. As a workaround, the user can declare these dependencies in the package.json file, but it is expected that this should not be necessary.

Reproduction Steps:

To reproduce the issue, the user initializes a Next.js app with TypeScript and then performs the following steps:

  1. Run the command npx create-next-app@9.5.2 my-app to create a Next.js app.
  2. Navigate into the app directory using cd my-app.
  3. Create a tsconfig.json file using touch tsconfig.json.
  4. Run npm run build to build the app.
  5. The error message suggests installing typescript, @types/react, and @types/node as they are missing.
  6. Install the missing dependencies using npm install --save-dev typescript @types/react @types/node.
  7. Run npm run build again.
  8. Edit tsconfig.json and set "strict": true and "skipLibCheck": false.
  9. Attempt to build the app again with npm run build.
  10. The build fails with TypeScript errors related to missing type definition files for 'react-dom'.
  11. Install the missing @types/react-dom dependency using npm install --save-dev @types/react-dom.
  12. Run npm run build once more.
  13. A new error occurs, indicating the need to install @types/webpack.
  14. Install @types/webpack with npm install --save-dev @types/webpack.
  15. Finally, running npm run build results in a successful build.

Troubleshooting with the Lightrun Developer Observability Platform

 

Getting a sense of what’s actually happening inside a live application is a frustrating experience, one that relies mostly on querying and observing whatever logs were written during development.
Lightrun is a Developer Observability Platform, allowing developers to add telemetry to live applications in real-time, on-demand, and right from the IDE.

  • Instantly add logs to, set metrics in, and take snapshots of live applications
  • Insights delivered straight to your IDE or CLI
  • Works where you do: dev, QA, staging, CI/CD, and production

Start for free today

Problem solution for TypeScript errors due to missing @types/react-dom and @types/webpack when using `”strict”: true` and `”skipLibCheck”: false`

 

One solution that has worked for others is to install all the necessary packages, perform the build, and then prune the dev dependencies. The process involves executing the following commands:

  1. Run npm ci to install all the packages.
  2. Execute npm run build to initiate the build process.
  3. After the build is complete, use npm prune --production to remove the unnecessary dev dependencies.
  4. Finally, start the application with npm run start.

While this solution works, it would be ideal if the error didn’t occur in the first place. It would be more convenient if we could simply execute npm ci --production followed by the build process without encountering the error.

Problems with next.js

 

  1. Performance issues with server-side rendering (SSR):

Problem Description: When using server-side rendering in Next.js, performance issues can arise due to inefficient rendering or excessive data fetching. This can lead to slow page load times and poor user experience.

Solution: To improve SSR performance in Next.js, optimize rendering and data fetching processes. Use the getStaticProps or getServerSideProps methods to pre-fetch data and render the page with the required data. Implement caching mechanisms to avoid unnecessary data fetches. Additionally, leverage features like incremental static regeneration (revalidate option) to update data at regular intervals without re-rendering the entire page.

Code Example:

 

// pages/index.js
import { getStaticProps } from 'next';

export function HomePage({ data }) {
  // Render the page using the fetched data
}

export async function getStaticProps() {
  const data = await fetch('https://api.example.com/data');
  // Process data and return it as props
  return {
    props: {
      data,
    },
    revalidate: 60, // Re-generate the page every 60 seconds
  };
}

 

  1. Handling authentication and authorization:

Problem Description: Next.js applications often require authentication and authorization mechanisms to restrict access to certain routes or components. Implementing secure authentication and authorization flows can be challenging.

Solution: Utilize authentication libraries or frameworks like NextAuth.js or JWT (JSON Web Tokens) to handle user authentication and authorization. Implement protected routes that check the user’s authentication status and role/permissions before rendering certain components or pages. Use server-side or API routes to handle authentication requests and store session data securely.

Code Example:

 

// pages/dashboard.js
import { getSession } from 'next-auth/client';

export function DashboardPage({ user }) {
  // Render the dashboard page for authenticated users
}

export async function getServerSideProps(context) {
  const session = await getSession(context);
  if (!session) {
    // Redirect unauthenticated users
    return {
      redirect: {
        destination: '/login',
        permanent: false,
      },
    };
  }
  // Retrieve user data and pass it as props
  return {
    props: {
      user: session.user,
    },
  };
}

 

  1. CSS and styling challenges:

Problem Description: Working with CSS and styles in Next.js can be complex, especially when dealing with global styles, CSS frameworks, or CSS-in-JS solutions. Conflicts, styling inconsistencies, and class name collisions are common issues.

Solution: Leverage CSS modules, CSS-in-JS libraries (e.g., styled-components, emotion), or CSS frameworks (e.g., Tailwind CSS) to encapsulate styles and avoid conflicts. Use CSS reset or normalize styles to establish a consistent baseline. Optimize CSS delivery by extracting critical CSS and deferring non-critical styles. Additionally, leverage Next.js’s built-in support for CSS modules to scope styles to specific components.

Code Example:

 

// components/Button.js
import styles from './Button.module.css';

export function Button({ children }) {
  return <button className={styles.button}>{children}</button>;
}

// Button.module.css
.button {
  /* Styles specific to the Button component */
}

 

A brief introduction to Next.js

 

Next.js is a popular open-source JavaScript framework used for building server-rendered React applications. It provides a powerful set of features and optimizations to facilitate the development of scalable and performant web applications. With Next.js, developers can leverage server-side rendering (SSR), static site generation (SSG), and client-side rendering (CSR) based on their specific needs.

At its core, Next.js enables server-side rendering, allowing web pages to be pre-rendered on the server and sent to the client as HTML. This approach improves initial page load times, enhances search engine optimization (SEO), and provides a better user experience. Next.js also supports static site generation, where pages can be pre-built at build time and served as static files, reducing the need for server-side processing. Additionally, Next.js supports hybrid rendering, combining both server-side rendering and client-side rendering to achieve the benefits of both approaches.

Next.js offers an intuitive file-based routing system, where each page is represented by a corresponding file in the pages directory. This simplifies the organization of the application’s codebase and makes it easy to create new pages. Next.js also provides a rich collection of features, including automatic code splitting, dynamic imports, serverless functions, API routes, and optimized image loading. It integrates seamlessly with popular frameworks and libraries like React, enabling developers to leverage their existing knowledge and ecosystem.

In summary, Next.js is a versatile framework that combines the power of React with server-side rendering and static site generation. It offers a comprehensive set of features and optimizations to streamline the development of high-performance web applications. Its flexible architecture, intuitive routing system, and extensive ecosystem make it a preferred choice for building modern web experiences.

 

Most popular use cases for Next.js

  1. Server-Side Rendering (SSR): Next.js is commonly used for implementing server-side rendering, allowing web pages to be rendered on the server and sent to the client as HTML. This enables faster initial page loads, improved SEO, and enhanced user experience. By leveraging Next.js’s built-in server-side rendering capabilities, developers can easily create dynamic and interactive web applications that perform well.

Example code for server-side rendering in Next.js:

// pages/index.js
import React from 'react';

const HomePage = ({ data }) => {
  return (
    <div>
      <h1>Welcome to Next.js!</h1>
      <p>Data: {data}</p>
    </div>
  );
};

export async function getServerSideProps() {
  // Fetch data from an API
  const response = await fetch('https://api.example.com/data');
  const data = await response.json();

  return {
    props: {
      data,
    },
  };
}

export default HomePage;
  1. Static Site Generation (SSG): Next.js also supports static site generation, where pages are pre-rendered at build time and served as static files. This approach offers improved performance and scalability by reducing the need for server-side processing. Next.js allows developers to generate dynamic content during the build process, making it possible to create highly optimized and SEO-friendly static websites.

Example code for static site generation in Next.js:

// pages/blog/[slug].js
import React from 'react';

const BlogPost = ({ post }) => {
  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
};

export async function getStaticPaths() {
  // Fetch list of blog post slugs from an API
  const response = await fetch('https://api.example.com/blog');
  const slugs = await response.json();

  // Generate paths for all blog posts
  const paths = slugs.map((slug) => ({ params: { slug } }));

  return {
    paths,
    fallback: false,
  };
}

export async function getStaticProps({ params }) {
  // Fetch blog post data based on the slug
  const response = await fetch(`https://api.example.com/blog/${params.slug}`);
  const post = await response.json();

  return {
    props: {
      post,
    },
  };
}

export default BlogPost;
  1. API Routes: Next.js provides built-in API routes, allowing developers to create serverless API endpoints within their Next.js applications. This eliminates the need for a separate backend server and enables seamless integration with frontend code. Developers can define API routes by creating files inside the pages/api directory. Here’s an example of a simple API route in Next.js:
// pages/api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello, World!' });
}
The above code creates an API endpoint at /api/hello that returns a JSON response with a greeting message. These API routes can be used to handle data fetching, form submissions, authentication, and more, making Next.js a versatile framework for building full-stack web applications.
Share

It’s Really not that Complicated.

You can actually understand what’s going on inside your live applications.

Try Lightrun’s Playground

Lets Talk!

Looking for more information about Lightrun and debugging?
We’d love to hear from you!
Drop us a line and we’ll get back to you shortly.

By clicking Submit I agree to Lightrun’s Terms of Use.
Processing will be done in accordance to Lightrun’s Privacy Policy.