Tuesday, November 28, 2023

React 18 Webpack 5 New Jest Testing with Server Side Rendering

  We are using Webpack 5.89 and related package.  


https://github.com/harshal1982/react18-ssr


    Basic Project Structure





Package.json

{
  "name": "harshal-ssr",
  "version": "2.0.1",
  "description": "Server side rendering project",
  "main": "index.js",
  "scripts": {
    "clean:build": "rimraf build public",
    "dev": "npm run clean:build && webpack --mode development --watch",
    "test": "jest --coverage -u"
  },
 
  "author": "",
  "license": "ISC",
  "jest": {
    "transform": {
      "^.+\\.(js|ts)$": "babel-jest"
    },
    "transformIgnorePatterns": [],
    "testEnvironment": "jsdom",
    "moduleNameMapper": {
      "\\.(css|less|scss)$": "<rootDir>/tests/css/__mocks__/styleMock.js"
    }
  },
  "dependencies": {
    "@babel/polyfill": "^7.12.1",
    "@babel/preset-typescript": "^7.23.2",
    "@babel/register": "^7.22.15",
    "@reduxjs/toolkit": "^1.9.7",
    "async_hooks": "^1.0.0",
    "axios": "^1.6.0",
    "babel-loader": "^9.1.3",
    "compression": "^1.7.4",
    "concurrently": "^8.2.2",
    "copy-webpack-plugin": "^11.0.0",
    "express": "^4.18.2",
    "express-http-proxy": "^2.0.0",
    "fs": "^0.0.1-security",
    "lodash": "^4.17.21",
    "net": "^1.0.2",
    "nodemon": "^3.0.1",
    "nodemon-webpack-plugin": "^4.8.2",
    "npm-run-all": "^4.1.5",
    "path": "^0.12.7",
    "progress-bar-webpack-plugin": "^2.1.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-helmet": "^6.1.0",
    "react-redux": "^8.1.3",
    "react-router-config": "^5.1.1",
    "react-router-dom": "^6.18.0",
    "redux": "^4.2.1",
    "redux-thunk": "^2.4.2",
    "rimraf": "^5.0.5",
    "serialize-javascript": "^6.0.1",
    "webpack": "^5.89.0",
    "webpack-cli": "^5.1.4",
    "webpack-dev-server": "^4.15.1",
    "webpack-merge": "^5.10.0",
    "webpack-node-externals": "^3.0.0"
  },
  "devDependencies": {
    "@babel/core": "^7.23.2",
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/plugin-transform-runtime": "^7.23.2",
    "@babel/preset-env": "^7.23.3",
    "@babel/preset-react": "^7.23.3",
    "@testing-library/jest-dom": "^6.1.4",
    "@testing-library/react": "^14.1.2",
    "@testing-library/react-hooks": "^8.0.1",
    "babel-jest": "^29.7.0",
    "css-loader": "^6.8.1",
    "html-webpack-plugin": "^5.5.3",
    "jest": "^29.7.0",
    "jest-environment-jsdom": "^29.7.0",
    "mini-css-extract-plugin": "^2.7.6",
    "node-polyfill-webpack-plugin": "^2.0.1",
    "nyc": "^15.1.0",
    "react-test-renderer": "^18.2.0",
    "redux-mock-store": "^1.5.4",
    "sass": "^1.69.5",
    "sass-loader": "^13.3.2",
    "style-loader": "^3.3.3",
    "webpack-manifest-plugin": "^5.0.0"
  }
}



webpack.config.js

module.exports = require(`./config/webpack.${process.env.NODE_ENV || 'development'}.js`);



.babelrc


{
    "presets": ["@babel/preset-env", "@babel/preset-react"],
    "plugins": [ "@babel/plugin-transform-runtime","@babel/plugin-proposal-class-properties"]
}


config/webpack.client.common.js


const MiniCssExtractPlugin = require('mini-css-extract-plugin');


const config = {
  module: {
    rules: [
      {
        test: /\.?js|jsx$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
          },
        },
      },
      {
        test: /\.(svg|jpg|jpeg|png|gif|pdf)$/,
        exclude: /fonts/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: './images/[name].[ext]',
              publicPath: '/',
            },
          },
        ],
      },
      {
        test: /\.(scss|css)$/,
        exclude: /node_modules/,
        use: ['style-loader', 'css-loader', 'sass-loader'],
      },
    ],
  },
};

module.exports = config;

config/webpack.development.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const ProgressBarPlugin = require('progress-bar-webpack-plugin');
const WebpackManifestPlugin = require('webpack-manifest-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const NodemonPlugin = require('nodemon-webpack-plugin');
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const clientcommonconfig = require('./webpack.client.common');
const servercommonconfig = require('./webpack.server.common')
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const clientConfig = merge(clientcommonconfig, {
  mode: 'development',
  target: 'web',
  entry: './src/app/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, '../public'),
   
  },

 
  plugins: [
    new ProgressBarPlugin(),
    new CopyWebpackPlugin({
        patterns: [
          {from: "src/images", to: "images/"}
        ],
      }),
    new webpack.DefinePlugin({
      HTTP_DEFAULT_TIMEOUT: 5000,
    }),
  ],
});

const serverConfig =  merge(servercommonconfig, {
  mode: 'development',
  target: 'node',
  entry: './src/server/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, '../build'),
   
  },
  externals: [nodeExternals()],  
  plugins: [
    new ProgressBarPlugin(),
   
    new NodePolyfillPlugin(),
    new NodemonPlugin({
      watch: path.resolve('../build'),
      ext: 'js,json',
      filename: 'server.js',
      verbose: true,
      env: {
        NODE_ENV: 'development',
      },
    }),
    new webpack.DefinePlugin({
      HTTP_DEFAULT_TIMEOUT: 5000,
    }),
  ],
});

module.exports = [clientConfig, serverConfig];


config/webpack.server.common.js


const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const config = {
  module: {
    rules: [
      {
        test: /\.?js|jsx$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
          },
        },
      },
      {
        test:/\.(scss|css)$/,
        exclude: /node_modules/,
        use: ['style-loader','css-loader', 'sass-loader'],
      },
    ],
  },
};

module.exports = config;

Labels:

Friday, November 9, 2012

 Simple Drop down HTML

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>CSS Dropdown Menu</title>

<link href="style.css" rel="stylesheet" />

</head>
<body>

<nav>
 <ul>
  <li><a href="#">Home</a></li>
  <li><a href="#">Tutorials</a>
   <ul>
    <li><a href="#">Photoshop</a></li>
    <li><a href="#">Illustrator</a></li>
    <li><a href="#">Web Design</a>
     <ul>
      <li><a href="#">HTML</a></li>
      <li><a href="#">CSS</a></li>
     </ul>
    </li>
   </ul>
  </li>
  <li><a href="#">Articles</a>
   <ul>
    <li><a href="#">Web Design</a></li>
    <li><a href="#">User Experience</a></li>
   </ul>
  </li>
  <li><a href="#">Inspiration</a></li>
 </ul>
</nav>

</body>
</html>
 
style.css at same location
 
 
body, div, h1, h2, h3, h4, h5, h6, p, ul, ol, li, dl, dt, dd, img, form, fieldset, input, textarea, blockquote {
 margin: 0; padding: 0; border: 0;
}

body {
 background: #909eab url(bg.png);
 font-family: Helvetica, sans-serif; font-size: 18px; line-height: 24px;
}

nav {
 margin: 100px auto; 
 text-align: center;
}

nav ul ul {
 display: none;
}

 nav ul li:hover > ul {
  display: block;
 }


nav ul {
 background: #efefef; 
 background: linear-gradient(top, #efefef 0%, #bbbbbb 100%);  
 background: -moz-linear-gradient(top, #efefef 0%, #bbbbbb 100%); 
 background: -webkit-linear-gradient(top, #efefef 0%,#bbbbbb 100%); 
 box-shadow: 0px 0px 9px rgba(0,0,0,0.15);
 padding: 0 20px;
 border-radius: 10px;  
 list-style: none;
 position: relative;
 display: inline-table;
}
 nav ul:after {
  content: ""; clear: both; display: block;
 }

 nav ul li {
  float: left;
 }
  nav ul li:hover {
   background: #4b545f;
   background: linear-gradient(top, #4f5964 0%, #5f6975 40%);
   background: -moz-linear-gradient(top, #4f5964 0%, #5f6975 40%);
   background: -webkit-linear-gradient(top, #4f5964 0%,#5f6975 40%);
  }
   nav ul li:hover a {
    color: #fff;
   }
  
  nav ul li a {
   display: block; padding: 25px 40px;
   color: #757575; text-decoration: none;
  }
   
  
 nav ul ul {
  background: #5f6975; border-radius: 0px; padding: 0;
  position: absolute; top: 100%;
 }
  nav ul ul li {
   float: none; 
   border-top: 1px solid #6b727c;
   border-bottom: 1px solid #575f6a; position: relative;
  }
   nav ul ul li a {
    padding: 15px 40px;
    color: #fff;
   } 
    nav ul ul li a:hover {
     background: #4b545f;
    }
  
 nav ul ul ul {
  position: absolute; left: 100%; top:0;
 }