How to bundle React component as NPM package that is ready for server side rendering?

Viewed 177

I created a React component and published it as package on NPM. It works as planed on client side, however, when I try to do ssr with next.js it crashes with error ReferenceError: document is not defined. Through simple search I found that my bundle and my component depends on existence of document. It is important to note my package does not use react-dom.

How do I bundle the component/s with webpack so the package can be imported and used in ssr applications?

I tried changing the target and libraryTarget, but I was not able to achieve what I needed. Also, through research I found that often people write two different code in their packages for client side and server side rendering. However, I could not find how to write react component for ssr and how it could exclude document from it. If it is true that one needs to write React component specifically for server, then how can it be done?

Bellow I am sending my webpack configuration.

Webpack

const nodeExternals = require('webpack-node-externals')

const web = {
  mode: 'production',
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'index.js',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    extensions: ['.ts', '.tsx'],
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /(node_modules|bower_components)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
            },
          },
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.ts$|.tsx$/,
        use: 'ts-loader',
      },
    ],
  },
  externals: {
    react: 'commonjs react',
    'react-apollo': 'commonjs react-apollo',
    graphql: 'commonjs graphql',
    'graphql-tag': 'commonjs graphql-tag',
  },
}

const node = {
  mode: 'production',
  entry: './src/index.ts',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: 'index.node.js',
    libraryTarget: 'commonjs2',
  },
  resolve: {
    extensions: ['.ts', '.tsx'],
  },
  target: 'node',
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve(__dirname, 'src'),
        exclude: /(node_modules|bower_components)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
            },
          },
        ],
      },
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
      },
      {
        test: /\.ts$|.tsx$/,
        use: 'ts-loader',
      },
    ],
  },
  externals: [
    nodeExternals(),
    {
      react: 'commonjs react',
      'react-apollo': 'commonjs react-apollo',
      graphql: 'commonjs graphql',
      'graphql-tag': 'commonjs graphql-tag',
    },
  ],
}

module.exports = [web, node]```
0 Answers
Related