Oliver Johansson
Oliver Johansson

Reputation: 13

VITE app with MSW - issue after deployment

I have a frontend-backend project that is usually run with dotnent when we run the full-scale application. But now i have also created a completely mock-based site using MSW ( mock-service-worker ). This works just fine locally but after deployment i get a white screen from time to time on the deployed site. Sometimes it works and sometimes it doesnt, usually works after a reload of page. Ive tried various solutions but i cant really get it to work without the white-page from time to time. Anyone who has any suggestions?

Vite.config:

import { defineConfig, loadEnv } from 'vite';
import https from 'https';
import path from 'path';
import fs from 'fs';
import tsconfigPaths from 'vite-tsconfig-paths';
import react from '@vitejs/plugin-react';
import basicSsl from '@vitejs/plugin-basic-ssl';
import { visualizer } from 'rollup-plugin-visualizer';

// Enable visualizer when we are working with it
// import { visualizer } from 'rollup-plugin-visualizer';

function excludeMsw() {
    return {
        name: 'exclude-msw',
        resolveId(source) {
            return source === 'virtual-module' ? source : null;
        },
        renderStart(outputOptions, _inputOptions) {
            const outDir = outputOptions.dir;
            const msWorker = path.resolve(outDir, 'mockServiceWorker.js');
            fs.rm(msWorker, () => console.log(`Deleted ${msWorker}`));
        },
    };
}

function translationReload() {
    return {
        // Since we are getting our translations with a http request
        // We need to refetch them when any changes are made. Therefore we do a reload
        name: 'translation-reload',
        handleHotUpdate({ file, server }) {
            if (file.includes('locales') && file.endsWith('.json')) {
                const filePath = path.dirname(file);
                const fileFolder = filePath.substring(filePath.lastIndexOf('/') + 1);
                console.log(`Translation updated: ${fileFolder}/${path.basename(file)}. Reloading`);

                server.ws.send({
                    type: 'full-reload',
                    path: '*',
                });
            }
        },
    };
}
export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, process.cwd());

    const proxyContext = [
        '/auth',
        '/api',
        '/loansapi',
        '/cardsapi',
        '/complianceapi',
        '/savingsapi',
        '/kreditzapi',
        '/consentapi',
        '/edgeapi',
    ];
    const proxySettings = {
        target: env.VITE_PROXY_TARGET || `https://localhost:44349`,
        changeOrigin: true,
        secure: false,
        agent: new https.Agent(),
    };

    const proxy = proxyContext.reduce((result, path) => {
        return { ...result, [path]: proxySettings };
    }, {});

    return {
        plugins: [
            react({
                jsxImportSource: '@emotion/react',
                babel: {
                    plugins: ['@emotion/babel-plugin'],
                },
            }),
            tsconfigPaths(),
            env.VITE_ENV !== 'development' ? basicSsl() : null,
            translationReload(),
            excludeMsw(),
            // visualizer({
            //     filename: 'bundle-analysis.html',
            //     open: true,
            // }),
        ],
        define: {
            'process.env': env,
        },
        server: {
            allowedHosts: ['mocked-frontend-domain'],
            proxy: env.VITE_ENV !== 'development' ? proxy : {},
            https: env.VITE_ENV !== 'development',
            open: false,
            secure: false,
            port: 3000,
            watch: {
                usePolling: true,
            },
        },
        base: '/',
        build: {
            // Relative to the root
            outDir: './build',
            target: 'es2015',
            rollupOptions: {
                output: {
                    chunkFileNames: '[hash].js',
                    manualChunks: id => {
                        if (id.includes('features/applications/loans')) {
                            return 'vendor_loan_application';
                        }

                        if (id.includes('features/applications/savings')) {
                            return 'vendor_savings_application';
                        }

                        if (id.includes('features/applications/card')) {
                            return 'vendor_card_applications';
                        }

                        if (id.includes('src/features')) {
                            return 'vendor_features';
                        }

                        if (id.includes('node_modules')) {
                            if (id.includes('@mui/x-date-pickers')) {
                                return 'vendor_mui_date_pickers';
                            }

                            if (id.includes('@mui')) {
                                return 'vendor_mui';
                            }

                            if (id.includes('storybook')) {
                                return 'vendor_storybook';
                            }

                            if (id.includes('launchdarkly')) {
                                return 'vendor_launchdarkly';
                            }

                            if (id.includes('date-fns')) {
                                return 'vendor_datefns';
                            }

                            if (id.includes('i18next')) {
                                return 'vendor_i18next';
                            }

                            if (id.includes('react-query')) {
                                return 'vendor_reactquery';
                            }
                            // all other package goes here
                            return 'vendor';
                        }
                    },
                },
            },
        },
        test: {
            globals: true,
            environment: 'jsdom',
            setupFiles: './scripts/setupTest.js',
            exclude: ['e2e', 'node_modules/**/*', 'tests'],
        },
        resolve: {
            preserveSymlinks: true,
        },
    };
});

Dockerfile:

FROM node:18-alpine

RUN specific fun commad ***

USER mock

WORKDIR /home/mock/app

COPY --chown=mock:mock package.json ./

RUN npm install

COPY --chown=mock:mock . .

RUN npm run build

ENV TMPDIR=/tmp

ENV VITE_CACHE_DIR=/tmp/vite-cache

EXPOSE 3000

CMD ["npm", "run", "dev"]

Package.json

{
    "name": "NAME",
    "version": "4.4.0",
    "type": "module",
    "description": "DESCRIPTION",
    "main": "index.js",
    "scripts": {
        "prestart": "node scripts/aspnetcore-https.js && node scripts/setupEnv.js",
        "dev": "cross-env VITE_ENV=development npm run serve",
        "start": "npm run serve",
        "serve": "vite serve --port 3000 --host",
        "test:jest": "cross-env VITE_TEST=true vitest",
        "test": "cross-env VITE_TEST=true vitest && npm run test:e2e",
        "test:e2e": "playwright test",
        "test:generate": "npm run dev & npx playwright codegen http://localhost:3000/overview",
        "test:e2e:ci": "npx playwright test",
        "test:noWatch": "vitest run",
        "lint": "eslint src --ext .ts,.tsx --quiet --fix",
        "tslint": "npx tsc --noEmit --project tsconfig.json",
        "build": "npx msw init ./public && vite build",
        "storybook": "storybook dev -p 6006 -s public",
        "build-storybook": "storybook build"
    },
    "repository": {
        "type": "git",
        "url": ""
    },
    "license": "MIT",
    "browserslist": "last 2 versions, > 1%",
    "dependencies": {
        "@emotion/react": "^11.13.3",
        "@emotion/styled": "^11.13.0",
        "@hookform/resolvers": "^3.9.0",
        "@mui/material": "^5.16.3",
        "@mui/x-date-pickers": "^7.0.8",
        "@opendevtools/clearingnummer": "^1.3.0",
        "@tanstack/react-query": "^4.36.1",
        "@tanstack/react-query-devtools": "^4.36.1",
        "@types/react-dom": "^18.3.0",
        "@types/react-recaptcha-v3": "^1.1.5",
        "date-fns": "^2.29.3",
        "i18n-iso-countries": "^7.5.0",
        "i18next": "^24.0.2",
        "i18next-http-backend": "^2.0.1",
        "launchdarkly-react-client-sdk": "^3.0.6",
        "next-i18next": "^15.3.1",
        "polished": "^4.2.2",
        "qrcode.react": "^3.1.0",
        "react": "18.3.1",
        "react-dom": "18.3.1",
        "react-ga4": "^2.0.0",
        "react-google-recaptcha-v3": "^1.10.1",
        "react-hook-form": "^7.53.0",
        "react-i18next": "^15.1.0",
        "react-router-dom": "6.11.1",
        "uuid": "^9.0.0",
        "whatwg-fetch": "3.0.0",
        "yup": "^1.4.0"
    },
    "devDependencies": {
        "@playwright/test": "^1.40.1",
        "@storybook/addon-essentials": "7.4.5",
        "@storybook/addon-interactions": "7.4.5",
        "@storybook/addon-links": "7.4.5",
        "@storybook/blocks": "7.4.5",
        "@storybook/react": "7.4.5",
        "@storybook/react-vite": "8.0.0",
        "@storybook/testing-library": "0.2.1",
        "@storybook/theming": "7.4.5",
        "@testing-library/dom": "^10.4.0",
        "@testing-library/jest-dom": "^6.5.0",
        "@testing-library/react": "^16.0.1",
        "@types/jest": "^29.5.12",
        "@types/react": "18.3.2",
        "@types/testing-library__dom": "6.14.0",
        "@types/uuid": "^9.0.2",
        "@typescript-eslint/eslint-plugin": "^5.43.0",
        "@typescript-eslint/parser": "^5.43.0",
        "@vitejs/plugin-basic-ssl": "^1.0.1",
        "@vitejs/plugin-react": "^4.0.0",
        "babel-plugin-emotion": "11.0.0",
        "cross-env": "^7.0.3",
        "dotenv": "^16.0.1",
        "eslint": "^8.2.0",
        "eslint-config-airbnb": "^19.0.4",
        "eslint-config-airbnb-typescript": "^17.0.0",
        "eslint-config-prettier": "^8.5.0",
        "eslint-plugin-import": "^2.26.0",
        "eslint-plugin-jsx-a11y": "^6.6.1",
        "eslint-plugin-prettier": "^4.2.1",
        "eslint-plugin-react": "^7.35.2",
        "eslint-plugin-react-hooks": "^4.6.0",
        "eslint-plugin-storybook": "^0.6.14",
        "eslint-plugin-unused-imports": "^2.0.0",
        "jsdom": "^20.0.3",
        "msw": "^1.3.2",
        "msw-storybook-addon": "^1.8.0",
        "prettier": "2.7.0",
        "rollup-plugin-visualizer": "^5.9.0",
        "sass": "^1.56.1",
        "storybook": "^8.0.0",
        "typescript": "^5.5.4",
        "vite": "^5.4.14",
        "vite-tsconfig-paths": "^4.2.0",
        "vitest": "^2.1.6"
    },
    "resolutions": {
        "@types/react": "18.3.5",
        "@types/react-dom": "18.3.0"
    },
    "msw": {
        "workerDirectory": "public"
    }
}

Upvotes: 0

Views: 32

Answers (0)

Related Questions