Migrate from create react app to vite

This commit is contained in:
Przemek Więch 2025-02-05 17:05:34 +01:00
parent 99a217191b
commit b3f5ae1c25
22 changed files with 3751 additions and 21797 deletions

2
.gitignore vendored
View File

@ -1,4 +1,4 @@
build
dist
node_modules
src/react-app-env.d.ts
cypress/fixtures/example.json

View File

@ -96,7 +96,7 @@ cd topola-viewer
npm install
npm run build
```
Now, take the contents of the `build/` folder and host it on your own server.
Now, take the contents of the `dist/` folder and host it on your own server.
### Use an existing package
@ -107,18 +107,18 @@ These are the exact files that are hosted on GitHub pages.
### Build for your own data only
You can run Topola Viewer in a "single tree mode" that displays only the GEDCOM you specify. Specify the URL to a GEDCOM file in the `REACT_APP_STATIC_URL` environment variable when building and running the application.
You can run Topola Viewer in a "single tree mode" that displays only the GEDCOM you specify. Specify the URL to a GEDCOM file in the `VITE_STATIC_URL` environment variable when building and running the application.
Run locally with the specified data URL:
```
REACT_APP_STATIC_URL=https://example.org/sample.ged npm start
VITE_STATIC_URL=https://example.org/sample.ged npm start
```
Build with the specified data URL:
```
REACT_APP_STATIC_URL=https://example.org/sample.ged npm run build
VITE_STATIC_URL=https://example.org/sample.ged npm run build
```
The `build/` folder will contain files that can be hosted on a Web server.
The `dist/` folder will contain files that can be hosted on a Web server.
### Alternative build

View File

@ -4,7 +4,7 @@ set -e
echo Copying files...
lftp --env-password sftp://wiech13@apps.wikitree.com << EOF
mkdir www/topola-viewer.new
mirror -R -p build/ www/topola-viewer.new/
mirror -R -p dist/ www/topola-viewer.new/
rm -r www/topola-viewer.old
mv www/topola-viewer www/topola-viewer.old
mv www/topola-viewer.new www/topola-viewer

View File

@ -19,5 +19,6 @@
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

21
jest.config.ts Normal file
View File

@ -0,0 +1,21 @@
import type { Config } from '@jest/types';
const config: Config.InitialOptions = {
testEnvironment: "node",
transform: {
"^.+.tsx?$": ["ts-jest", {}],
},
moduleNameMapper: {
"d3-array": "<rootDir>/node_modules/d3-array/dist/d3-array.js",
"d3-color": "<rootDir>/node_modules/d3-color/dist/d3-color.js",
"d3-ease": "<rootDir>/node_modules/d3-ease/dist/d3-ease.js",
"d3-dispatch": "<rootDir>/node_modules/d3-dispatch/dist/d3-dispatch.js",
"d3-interpolate": "<rootDir>/node_modules/d3-interpolate/dist/d3-interpolate.js",
"d3-hierarchy": "<rootDir>/node_modules/d3-hierarchy/dist/d3-hierarchy.js",
"d3-selection": "<rootDir>/node_modules/d3-selection/dist/d3-selection.js",
"d3-timer": "<rootDir>/node_modules/d3-timer/dist/d3-timer.js",
"d3-transition": "<rootDir>/node_modules/d3-transition/dist/d3-transition.js",
},
};
export default config;

25352
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -45,6 +45,7 @@
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@formatjs/fast-memoize": "^2.2.6",
"@formatjs/intl": "^2.10.15",
"@jest/globals": "^29.7.0",
"@types/adm-zip": "^0.5.0",
"@types/array.prototype.flatmap": "^1.2.2",
"@types/d3-array": "^3.2.1",
@ -63,30 +64,36 @@
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^4.19.0",
"@typescript-eslint/parser": "^4.19.0",
"@vitejs/plugin-react": "^4.3.4",
"cypress": "^13.17.0",
"gh-pages": "^6.3.0",
"jest": "^29.7.0",
"jsdom": "^26.0.0",
"prettier": "^3.4.2",
"react-scripts": "^5.0.1",
"run-script-os": "^1.1.6",
"start-server-and-test": "^2.0.9",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"tslint-config-prettier": "^1.18.0",
"typescript": "^4.9.5"
"typescript": "^5.7.3",
"vite": "^6.0.11",
"vite-tsconfig-paths": "^5.1.4"
},
"scripts": {
"start": "run-script-os",
"start:default": "GENERATE_SOURCEMAP=false REACT_APP_CHANGELOG=`cat CHANGELOG.md` REACT_APP_GIT_SHA=`git rev-parse --short HEAD` REACT_APP_GIT_TIME=`git log -1 --format=%ci` react-scripts start",
"start:windows": "set \"GENERATE_SOURCEMAP=false\" && react-scripts start",
"start:default": "GENERATE_SOURCEMAP=false VITE_CHANGELOG=`cat CHANGELOG.md` VITE_GIT_SHA=`git rev-parse --short HEAD` VITE_GIT_TIME=`git log -1 --format=%ci` vite",
"start:windows": "set \"GENERATE_SOURCEMAP=false\" && vite",
"build": "run-script-os",
"build:default": "GENERATE_SOURCEMAP=false REACT_APP_CHANGELOG=`cat CHANGELOG.md` REACT_APP_GIT_SHA=`git rev-parse --short HEAD` REACT_APP_GIT_TIME=`git log -1 --format=%ci` react-scripts build",
"build:windows": "set \"GENERATE_SOURCEMAP=false\" && react-scripts build",
"test": "react-scripts test --env=jsdom",
"build:default": "GENERATE_SOURCEMAP=false VITE_CHANGELOG=`cat CHANGELOG.md` VITE_GIT_SHA=`git rev-parse --short HEAD` VITE_GIT_TIME=`git log -1 --format=%ci` tsc && vite build",
"build:windows": "set \"GENERATE_SOURCEMAP=false\" && tsc && vite build",
"test": "jest",
"prettier": "prettier --write src/**/*.{ts,tsx,json} --end-of-line lf && prettier --write src/*.{ts,tsx,json} --end-of-line lf",
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"deploy": "gh-pages -d dist",
"predeploy-wikitree": "npm run build",
"deploy-wikitree": "./deploy-wikitree.sh",
"cy:run": "cypress run",
"cy:start-and-run": "BROWSER=none start-server-and-test start 3000 cy:run"
"cy:start-and-run": "BROWSER=none start-server-and-test start localhost:3000 cy:run"
},
"homepage": ".",
"browserslist": [
@ -100,17 +107,5 @@
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-use-before-define": "off"
}
},
"jest": {
"moduleNameMapper": {
"d3-array": "<rootDir>/node_modules/d3-array/dist/d3-array.js",
"d3-color": "<rootDir>/node_modules/d3-color/dist/d3-color.js",
"d3-ease": "<rootDir>/node_modules/d3-ease/dist/d3-ease.js",
"d3-hierarchy": "<rootDir>/node_modules/d3-hierarchy/dist/d3-hierarchy.js",
"d3-interpolate": "<rootDir>/node_modules/d3-interpolate/dist/d3-interpolate.js",
"d3-selection": "<rootDir>/node_modules/d3-selection/dist/d3-selection.js",
"d3-timer": "<rootDir>/node_modules/d3-timer/dist/d3-timer.js",
"d3-transition": "<rootDir>/node_modules/d3-transition/dist/d3-transition.js"
}
}
}

View File

@ -50,12 +50,12 @@ import {
import {DonatsoChart} from './donatso-chart';
/**
* Load GEDCOM URL from REACT_APP_STATIC_URL environment variable.
* Load GEDCOM URL from VITE_STATIC_URL environment variable.
*
* If this environment variable is provided, the viewer is switched to
* single-tree mode without the option to load other data.
*/
const staticUrl = process.env.REACT_APP_STATIC_URL;
const staticUrl = import.meta.env.VITE_STATIC_URL;
/** Shows an error message in the middle of the screen. */
function ErrorMessage(props: {message?: string}) {

View File

@ -19,8 +19,10 @@ export async function getChangelog(maxVersions: number, seenVersion?: string) {
? Date.parse(seenVersion.slice(0, 10))
: 0;
const changelog = import.meta.env.VITE_CHANGELOG as string;
const changes =
process.env.REACT_APP_CHANGELOG?.split('##')
changelog
.split('##')
.slice(1, maxVersions + 1)
.map((notes) => {
const date = Date.parse(notes.split('\n')[0].trim());
@ -40,7 +42,7 @@ export async function getChangelog(maxVersions: number, seenVersion?: string) {
/** Stores in local storage the current app version as the last seen version. */
export function updateSeenVersion() {
localStorage.setItem(LAST_SEEN_VERSION_KEY, process.env.REACT_APP_GIT_TIME!);
localStorage.setItem(LAST_SEEN_VERSION_KEY, import.meta.env.VITE_GIT_TIME!);
}
/**
@ -54,7 +56,7 @@ export function Changelog() {
useEffect(() => {
(async () => {
const seenVersion = localStorage.getItem(LAST_SEEN_VERSION_KEY);
const currentVersion = process.env.REACT_APP_GIT_TIME!;
const currentVersion = import.meta.env.VITE_GIT_TIME!;
if (!seenVersion || seenVersion === currentVersion) {
return;
}

View File

@ -1,3 +1,4 @@
import {expect, describe, it} from '@jest/globals';
import {loadFile} from './load_data';
import {readFileSync} from 'fs';
import {Blob} from 'buffer';

View File

@ -1 +0,0 @@
declare module '*.jpg';

View File

@ -1,3 +1,4 @@
import f3 from 'family-chart';
import {useEffect, useRef} from 'react';
import {IntlShape, useIntl} from 'react-intl';
import {IndiInfo, JsonFam, JsonGedcomData} from 'topola';
@ -5,8 +6,6 @@ import {IndiInfo, JsonFam, JsonGedcomData} from 'topola';
import {formatDateOrRange} from './util/date_util';
import {usePrevious} from './util/previous-hook';
const f3: any = require('family-chart');
export interface DonatsoChartProps {
data: JsonGedcomData;
selection: IndiInfo;

7
src/family-chart.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
// Data type definitions for the family-chart library.
declare module 'family-chart' {
export function createStore(args: any): any;
export function createSvg(args: any): any;
export function view(arg1: any, arg2: any, arg3: any, arg4: any): any;
export const elements: any;
}

2
src/imports.d.ts vendored
View File

@ -1,2 +1,2 @@
declare module '*.jng';
declare module '*.jpg';
declare module '*.png';

View File

@ -126,11 +126,11 @@ function Contents() {
/>
<p className="ui right aligned version">
version: {formatBuildDate(process.env.REACT_APP_GIT_TIME!)} (
version: {formatBuildDate(import.meta.env.VITE_GIT_TIME!)} (
<a
href={`https://github.com/PeWu/topola-viewer/commit/${process.env.REACT_APP_GIT_SHA}`}
href={`https://github.com/PeWu/topola-viewer/commit/${import.meta.env.VITE_GIT_SHA}`}
>
{process.env.REACT_APP_GIT_SHA}
{import.meta.env.VITE_GIT_SHA}
</a>
)
</p>

7
src/lunr-languages.d.ts vendored Normal file
View File

@ -0,0 +1,7 @@
declare module 'lunr-languages/lunr.*' {
import lunr from 'lunr';
function register(l: typeof lunr): void;
export = register;
}

View File

@ -3,12 +3,17 @@ import naturalSort from 'javascript-natural-sort';
import {idToFamMap, idToIndiMap} from '../util/gedcom_util';
import {JsonFam, JsonGedcomData, JsonIndi} from 'topola';
// TODO: Add type declarations and use import instead of require.
require('lunr-languages/lunr.stemmer.support')(lunr);
require('lunr-languages/lunr.de')(lunr);
require('lunr-languages/lunr.fr')(lunr);
require('lunr-languages/lunr.it')(lunr);
require('lunr-languages/lunr.ru')(lunr);
import lunrStemmer from 'lunr-languages/lunr.stemmer.support';
import lunrDe from 'lunr-languages/lunr.de';
import lunrFr from 'lunr-languages/lunr.fr';
import lunrIt from 'lunr-languages/lunr.it';
import lunrRu from 'lunr-languages/lunr.ru';
lunrStemmer(lunr);
lunrDe(lunr);
lunrFr(lunr);
lunrIt(lunr);
lunrRu(lunr);
const MAX_RESULTS = 8;

View File

@ -1,4 +1,4 @@
import expect from 'expect';
import {expect, describe, it} from '@jest/globals';
import {createIntl} from 'react-intl';
import {calcAge} from './age_util';

View File

@ -1,3 +1,4 @@
import {expect, describe, it} from '@jest/globals';
import {getName, normalizeGedcom} from './gedcom_util';
describe('normalizeGedcom()', () => {

1
src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es2020",
"lib": [
"dom",
"esnext"
@ -11,7 +11,7 @@
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,

15
vite.config.mts Normal file
View File

@ -0,0 +1,15 @@
import {defineConfig} from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
// depending on your application, base can also be "/"
base: '',
plugins: [react(), viteTsconfigPaths()],
server: {
// this ensures that the browser opens upon server start
open: true,
// this sets a default port to 3000
port: 3000,
},
});