parent
5c98e8f532
commit
a81692cd80
@ -0,0 +1,24 @@ |
|||||||
|
# Logs |
||||||
|
logs |
||||||
|
*.log |
||||||
|
npm-debug.log* |
||||||
|
yarn-debug.log* |
||||||
|
yarn-error.log* |
||||||
|
pnpm-debug.log* |
||||||
|
lerna-debug.log* |
||||||
|
|
||||||
|
node_modules |
||||||
|
dist |
||||||
|
dist-ssr |
||||||
|
*.local |
||||||
|
|
||||||
|
# Editor directories and files |
||||||
|
.vscode/* |
||||||
|
!.vscode/extensions.json |
||||||
|
.idea |
||||||
|
.DS_Store |
||||||
|
*.suo |
||||||
|
*.ntvs* |
||||||
|
*.njsproj |
||||||
|
*.sln |
||||||
|
*.sw? |
@ -0,0 +1,75 @@ |
|||||||
|
# example-webapp-react |
||||||
|
|
||||||
|
Example of a Web app made with NextGraph, using React and LDO, and Vite |
||||||
|
|
||||||
|
## NextGraph |
||||||
|
|
||||||
|
> NextGraph brings about the convergence of P2P and Semantic Web technologies, towards a decentralized, secure and privacy-preserving cloud, based on CRDTs. |
||||||
|
> |
||||||
|
> This open source ecosystem provides solutions for end-users (a platform) and software developers (a framework), wishing to use or create **decentralized** apps featuring: **live collaboration** on rich-text documents, peer to peer communication with **end-to-end encryption**, offline-first, **local-first**, portable and interoperable data, total ownership of data and software, security and privacy. Centered on repositories containing **semantic data** (RDF), **rich text**, and structured data formats like **JSON**, synced between peers belonging to permissioned groups of users, it offers strong eventual consistency, thanks to the use of **CRDTs**. Documents can be linked together, signed, shared securely, queried using the **SPARQL** language and organized into sites and containers. |
||||||
|
> |
||||||
|
> More info here [https://nextgraph.org](https://nextgraph.org) |
||||||
|
|
||||||
|
## For developing against a public Broker |
||||||
|
|
||||||
|
``` |
||||||
|
npm install |
||||||
|
npm run dev |
||||||
|
``` |
||||||
|
|
||||||
|
You will have to use a Wallet that was created on one of our public Broker Service Providers (nextgraph.eu by example). |
||||||
|
|
||||||
|
## For developing locally |
||||||
|
|
||||||
|
you need to have a running local ngd server. See those [instructions first](https://git.nextgraph.org/NextGraph/nextgraph-rs/src/branch/master/DEV.md#first-run). |
||||||
|
|
||||||
|
Then compile the nextgraphweb package in dev mode: |
||||||
|
|
||||||
|
``` |
||||||
|
pnpm run -C ../../helpers/nextgraphweb builddev |
||||||
|
``` |
||||||
|
|
||||||
|
``` |
||||||
|
npm install |
||||||
|
npm link ../../helpers/nextgraphweb |
||||||
|
npm run dev |
||||||
|
``` |
||||||
|
|
||||||
|
Due to the way `npm link` works, you will have to run this command again, after each time you use `npm install`. |
||||||
|
|
||||||
|
Open this URL in browser : [http://localhost:5173](http://localhost:5173) |
||||||
|
|
||||||
|
See the example code in [src/main.tsx](./src/main.tsx) |
||||||
|
|
||||||
|
## For usage in your project |
||||||
|
|
||||||
|
call : |
||||||
|
|
||||||
|
```javascript |
||||||
|
import {default as ng, init} from "nextgraphweb"; |
||||||
|
|
||||||
|
await init( location.origin, (event) => { |
||||||
|
// callback |
||||||
|
// once you receive event.status == "loggedin" |
||||||
|
// you can use the full API |
||||||
|
} |
||||||
|
, true // singleton: boolean (will your app create many docs in the system, or should it be launched as a unique instance) |
||||||
|
, []); //list of AccessRequests (for now, leave this empty) |
||||||
|
|
||||||
|
await ng.login(); // this will return false at the first attempt. but it will open the wallet login page so the user can login. |
||||||
|
// if you call it again later once the user has logged in already, it will return true, and nothing more will happen |
||||||
|
``` |
||||||
|
|
||||||
|
## License |
||||||
|
|
||||||
|
Licensed under either of |
||||||
|
|
||||||
|
- Apache License, Version 2.0 ([LICENSE-APACHE2](LICENSE-APACHE2) or http://www.apache.org/licenses/LICENSE-2.0) |
||||||
|
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) |
||||||
|
at your option. |
||||||
|
|
||||||
|
`SPDX-License-Identifier: Apache-2.0 OR MIT` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
NextGraph received funding through the [NGI Assure Fund](https://nlnet.nl/assure) and the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/), both funds established by [NLnet](https://nlnet.nl/) Foundation with financial support from the European Commission's [Next Generation Internet](https://ngi.eu/) programme, under the aegis of DG Communications Networks, Content and Technology under grant agreements No 957073 and No 101092990, respectively. |
@ -0,0 +1,28 @@ |
|||||||
|
import js from '@eslint/js' |
||||||
|
import globals from 'globals' |
||||||
|
import reactHooks from 'eslint-plugin-react-hooks' |
||||||
|
import reactRefresh from 'eslint-plugin-react-refresh' |
||||||
|
import tseslint from 'typescript-eslint' |
||||||
|
|
||||||
|
export default tseslint.config( |
||||||
|
{ ignores: ['dist'] }, |
||||||
|
{ |
||||||
|
extends: [js.configs.recommended, ...tseslint.configs.recommended], |
||||||
|
files: ['**/*.{ts,tsx}'], |
||||||
|
languageOptions: { |
||||||
|
ecmaVersion: 2020, |
||||||
|
globals: globals.browser, |
||||||
|
}, |
||||||
|
plugins: { |
||||||
|
'react-hooks': reactHooks, |
||||||
|
'react-refresh': reactRefresh, |
||||||
|
}, |
||||||
|
rules: { |
||||||
|
...reactHooks.configs.recommended.rules, |
||||||
|
'react-refresh/only-export-components': [ |
||||||
|
'warn', |
||||||
|
{ allowConstantExport: true }, |
||||||
|
], |
||||||
|
}, |
||||||
|
}, |
||||||
|
) |
@ -0,0 +1,12 @@ |
|||||||
|
<!doctype html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8" /> |
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||||
|
<title>NextGraph WebApp React example</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="app"></div> |
||||||
|
<script type="module" src="/src/main.tsx"></script> |
||||||
|
</body> |
||||||
|
</html> |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,35 @@ |
|||||||
|
{ |
||||||
|
"name": "example-webapp-react", |
||||||
|
"private": true, |
||||||
|
"version": "0.0.0", |
||||||
|
"type": "module", |
||||||
|
"scripts": { |
||||||
|
"dev": "vite", |
||||||
|
"build": "tsc -b && vite build", |
||||||
|
"lint": "eslint .", |
||||||
|
"preview": "vite preview" |
||||||
|
}, |
||||||
|
"dependencies": { |
||||||
|
"@ldo/connected-nextgraph": "^1.0.0-alpha.7", |
||||||
|
"@ldo/react": "^1.0.0-alpha.3", |
||||||
|
"nextgraphweb": "^0.1.1-alpha.1", |
||||||
|
"react": "^19.0.0", |
||||||
|
"react-dom": "^19.0.0" |
||||||
|
}, |
||||||
|
"devDependencies": { |
||||||
|
"@eslint/js": "^9.22.0", |
||||||
|
"@types/react": "^19.0.10", |
||||||
|
"@types/react-dom": "^19.0.4", |
||||||
|
"@vitejs/plugin-react": "^4.3.4", |
||||||
|
"autoprefixer": "^10.4.21", |
||||||
|
"eslint": "^9.22.0", |
||||||
|
"eslint-plugin-react-hooks": "^5.2.0", |
||||||
|
"eslint-plugin-react-refresh": "^0.4.19", |
||||||
|
"globals": "^16.0.0", |
||||||
|
"postcss": "^8.5.3", |
||||||
|
"tailwindcss": "^3.4.17", |
||||||
|
"typescript": "~5.7.2", |
||||||
|
"typescript-eslint": "^8.26.1", |
||||||
|
"vite": "^6.3.1" |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,6 @@ |
|||||||
|
export default { |
||||||
|
plugins: { |
||||||
|
tailwindcss: {}, |
||||||
|
autoprefixer: {}, |
||||||
|
}, |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
|
@ -0,0 +1,33 @@ |
|||||||
|
import { useState } from 'react' |
||||||
|
import React, { FunctionComponent } from 'react'; |
||||||
|
import { Header } from './Header'; |
||||||
|
import { Contact } from './Contact'; |
||||||
|
import { BrowserNGLdoProvider } from './reactMethods'; |
||||||
|
|
||||||
|
import './App.css' |
||||||
|
|
||||||
|
import "../../../common/src/styles.css"; |
||||||
|
|
||||||
|
// function App() {
|
||||||
|
// const [count, setCount] = useState(0)
|
||||||
|
|
||||||
|
// return (
|
||||||
|
// <div className="flex flex-col items-center justify-center h-screen bg-gray-100">
|
||||||
|
// <h1 className="text-4xl font-bold text-blue-600">Hello, Tailwind!</h1>
|
||||||
|
// <p className="mt-4 text-gray-700">Tailwind CSS is working in Vite!</p>
|
||||||
|
// </div>
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
const App: FunctionComponent = () => { |
||||||
|
return ( |
||||||
|
<div className="App"> |
||||||
|
<BrowserNGLdoProvider> |
||||||
|
<Header /> |
||||||
|
<Contact /> |
||||||
|
</BrowserNGLdoProvider> |
||||||
|
</div> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
export default App |
@ -0,0 +1,12 @@ |
|||||||
|
import { FunctionComponent } from "react"; |
||||||
|
import { useNextGraphAuth } from "./reactMethods"; |
||||||
|
|
||||||
|
export const Contact: FunctionComponent = () => { |
||||||
|
const { session } = useNextGraphAuth(); |
||||||
|
if (!session.sessionId) return <></>; |
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<p>Contact</p> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,43 @@ |
|||||||
|
import { FunctionComponent } from "react"; |
||||||
|
import { useNextGraphAuth } from "./reactMethods"; |
||||||
|
|
||||||
|
|
||||||
|
export const Header: FunctionComponent = () => { |
||||||
|
|
||||||
|
const { session, login, logout } = useNextGraphAuth(); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="full-layout"> |
||||||
|
|
||||||
|
{session.sessionId ? ( |
||||||
|
// If the session is logged in
|
||||||
|
<div className="p-1 text-center fixed top-0 left-0 right-0" style={{zIndex:1000, height:'36px', backgroundColor:'rgb(73, 114, 165)'}}> |
||||||
|
You are logged in. <span className="font-bold clickable" onClick={logout}> Log out</span> |
||||||
|
</div> |
||||||
|
) : ( |
||||||
|
// If the session is not logged in
|
||||||
|
<> |
||||||
|
<h1 className="text-2xl text-center mb-10">Welcome to your contact manager</h1> |
||||||
|
<div className="text-center text-xl p-1 text-white fixed top-0 left-0 right-0" style={{zIndex:1000, height:'36px', backgroundColor:'rgb(73, 114, 165)'}}> |
||||||
|
Please <span className="font-bold clickable" onClick={login}> Log in</span> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className="text-center max-w-6xl lg:px-8 mx-auto px-4 text-blue-800"> |
||||||
|
|
||||||
|
<svg className="mt-10 h-16 w-16 mx-auto" data-slot="icon" fill="none" strokeWidth="1.5" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> |
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" d="M8.25 9V5.25A2.25 2.25 0 0 1 10.5 3h6a2.25 2.25 0 0 1 2.25 2.25v13.5A2.25 2.25 0 0 1 16.5 21h-6a2.25 2.25 0 0 1-2.25-2.25V15M12 9l3 3m0 0-3 3m3-3H2.25"></path> |
||||||
|
</svg> |
||||||
|
|
||||||
|
<button |
||||||
|
onClick={login} |
||||||
|
onKeyUp={login} |
||||||
|
className="select-none ml-0 mt-2 mb-10 text-white bg-blue-800 hover:bg-primary-700/90 focus:ring-4 focus:ring-primary-500/50 rounded-lg text-base p-2 text-center inline-flex items-center dark:focus:ring-primary-700/55" |
||||||
|
> |
||||||
|
Please Log in |
||||||
|
</button> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,32 @@ |
|||||||
|
import { FormEvent, FunctionComponent, useCallback, useState } from "react"; |
||||||
|
|
||||||
|
export const MakePost: FunctionComponent = () => { |
||||||
|
const [name, setName] = useState(""); |
||||||
|
const [email, setEmail] = useState(""); |
||||||
|
|
||||||
|
const onSubmit = useCallback( |
||||||
|
async (e: FormEvent<HTMLFormElement>) => { |
||||||
|
e.preventDefault(); |
||||||
|
|
||||||
|
}, |
||||||
|
[name, email] |
||||||
|
); |
||||||
|
|
||||||
|
return ( |
||||||
|
<form onSubmit={onSubmit}> |
||||||
|
<input |
||||||
|
type="text" |
||||||
|
placeholder="Enter name" |
||||||
|
value={name} |
||||||
|
onChange={(e) => setName(e.target.value)} |
||||||
|
/> |
||||||
|
<input |
||||||
|
type="text" |
||||||
|
placeholder="Enter email address" |
||||||
|
value={email} |
||||||
|
onChange={(e) => setEmail(e.target.value)} |
||||||
|
/> |
||||||
|
<input type="submit" value="Post" /> |
||||||
|
</form> |
||||||
|
); |
||||||
|
}; |
@ -0,0 +1,20 @@ |
|||||||
|
import { createContext, useContext } from "react"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Functions for authenticating with NextGraph |
||||||
|
*/ |
||||||
|
export interface NGWalletAuthFunctions { |
||||||
|
login: () => Promise<void>; |
||||||
|
logout: () => Promise<void>; |
||||||
|
session: unknown; |
||||||
|
ranInitialAuthCheck: boolean; |
||||||
|
} |
||||||
|
|
||||||
|
// There is no initial value for this context. It will be given in the provider
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
|
export const NextGraphAuthContext = createContext<NGWalletAuthFunctions>(undefined); |
||||||
|
|
||||||
|
export function useNextGraphAuth(): NGWalletAuthFunctions { |
||||||
|
return useContext(NextGraphAuthContext); |
||||||
|
} |
@ -0,0 +1,108 @@ |
|||||||
|
import React, { useCallback, useEffect, useMemo, useState } from "react"; |
||||||
|
import type { FunctionComponent, PropsWithChildren } from "react"; |
||||||
|
import { NextGraphAuthContext, useNextGraphAuth } from "./NextGraphAuthContext"; |
||||||
|
|
||||||
|
import {default as ng, init} from "nextgraphweb"; |
||||||
|
|
||||||
|
import type { ConnectedLdoDataset, ConnectedPlugin } from "@ldo/connected"; |
||||||
|
import type { NextGraphConnectedPlugin, NextGraphConnectedContext } from "@ldo/connected-nextgraph"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates special react methods specific to the NextGraph Auth |
||||||
|
* @param dataset the connectedLdoDataset with a nextGraphConnectedPlugin |
||||||
|
* @returns { BrowserNGLdoProvider, useNextGraphAuth } |
||||||
|
*/ |
||||||
|
export function createBrowserNGReactMethods( |
||||||
|
dataset: ConnectedLdoDataset<(NextGraphConnectedPlugin | ConnectedPlugin)[]>, |
||||||
|
) { |
||||||
|
|
||||||
|
const BrowserNGLdoProvider: FunctionComponent<PropsWithChildren> = ({ |
||||||
|
children, |
||||||
|
}) => { |
||||||
|
const [session, setSession] = useState<NextGraphConnectedContext>( |
||||||
|
{ |
||||||
|
ng: undefined, |
||||||
|
} |
||||||
|
); |
||||||
|
const [ranInitialAuthCheck, setRanInitialAuthCheck] = useState(false); |
||||||
|
|
||||||
|
const runInitialAuthCheck = useCallback(async () => { |
||||||
|
console.log("runInitialAuthCheck called", ranInitialAuthCheck) |
||||||
|
if (ranInitialAuthCheck) return; |
||||||
|
|
||||||
|
console.log("init called"); |
||||||
|
setRanInitialAuthCheck(true); |
||||||
|
// TODO: export the types for the session object coming from NG.
|
||||||
|
await init( (event: { status: string; session: { session_id: unknown; protected_store_id: unknown; private_store_id: unknown; public_store_id: unknown; }; }) => { |
||||||
|
console.log("called back in react", event) |
||||||
|
|
||||||
|
// callback
|
||||||
|
// once you receive event.status == "loggedin"
|
||||||
|
// you can use the full API
|
||||||
|
if (event.status == "loggedin") { |
||||||
|
setSession({
|
||||||
|
ng,
|
||||||
|
sessionId: event.session.session_id as string, //FIXME: sessionId should be a Number.
|
||||||
|
protectedStoreId: event.session.protected_store_id as string, |
||||||
|
privateStoreId: event.session.private_store_id as string, |
||||||
|
publicStoreId: event.session.public_store_id as string |
||||||
|
}); // TODO: add event.session.user too
|
||||||
|
|
||||||
|
dataset.setContext("nextgraph", { |
||||||
|
ng, |
||||||
|
sessionId: event.session.session_id as string |
||||||
|
}); |
||||||
|
} |
||||||
|
else if (event.status == "cancelled" || event.status == "error" || event.status == "loggedout") { |
||||||
|
setSession({ ng: undefined }); |
||||||
|
dataset.setContext("nextgraph", { |
||||||
|
ng: undefined, |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
, true // singleton: boolean (will your app create many docs in the system, or should it be launched as a unique instance)
|
||||||
|
, []); //list of AccessRequests (for now, leave this empty)
|
||||||
|
|
||||||
|
}, []); |
||||||
|
|
||||||
|
|
||||||
|
const login = useCallback( |
||||||
|
async () => { |
||||||
|
await ng.login(); |
||||||
|
}, |
||||||
|
[], |
||||||
|
); |
||||||
|
|
||||||
|
const logout = useCallback(async () => { |
||||||
|
await ng.logout(); |
||||||
|
}, []); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
runInitialAuthCheck(); |
||||||
|
}, []); |
||||||
|
|
||||||
|
const nextGraphAuthFunctions = useMemo( |
||||||
|
() => ({ |
||||||
|
login, |
||||||
|
logout, |
||||||
|
session, |
||||||
|
}), |
||||||
|
[ |
||||||
|
login, |
||||||
|
logout, |
||||||
|
session, |
||||||
|
], |
||||||
|
); |
||||||
|
|
||||||
|
return ( |
||||||
|
<NextGraphAuthContext.Provider value={nextGraphAuthFunctions}> |
||||||
|
{children} |
||||||
|
</NextGraphAuthContext.Provider> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
return { |
||||||
|
BrowserNGLdoProvider, |
||||||
|
useNextGraphAuth: useNextGraphAuth |
||||||
|
}; |
||||||
|
}; |
@ -0,0 +1,3 @@ |
|||||||
|
@tailwind base; |
||||||
|
@tailwind components; |
||||||
|
@tailwind utilities; |
@ -0,0 +1,10 @@ |
|||||||
|
import { StrictMode } from 'react' |
||||||
|
import { createRoot } from 'react-dom/client' |
||||||
|
import './index.css' |
||||||
|
import App from './App.tsx' |
||||||
|
|
||||||
|
createRoot(document.getElementById('app')!).render( |
||||||
|
// <StrictMode>
|
||||||
|
<App /> |
||||||
|
// </StrictMode>,
|
||||||
|
) |
@ -0,0 +1,19 @@ |
|||||||
|
import { nextGraphConnectedPlugin } from "@ldo/connected-nextgraph"; |
||||||
|
import { createLdoReactMethods } from "@ldo/react"; |
||||||
|
import { createBrowserNGReactMethods } from "./createBrowserNGReactMethods"; |
||||||
|
|
||||||
|
|
||||||
|
export const { |
||||||
|
dataset, |
||||||
|
useLdo, |
||||||
|
useMatchObject, |
||||||
|
useMatchSubject, |
||||||
|
useResource, |
||||||
|
useSubject, |
||||||
|
useSubscribeToResource, |
||||||
|
} = createLdoReactMethods([nextGraphConnectedPlugin]); |
||||||
|
|
||||||
|
const methods = createBrowserNGReactMethods(dataset); |
||||||
|
|
||||||
|
export const { BrowserNGLdoProvider, useNextGraphAuth } = methods; |
||||||
|
|
@ -0,0 +1 @@ |
|||||||
|
/// <reference types="vite/client" />
|
@ -0,0 +1,12 @@ |
|||||||
|
/** @type {import('tailwindcss').Config} */ |
||||||
|
export default { |
||||||
|
content: [ |
||||||
|
"./index.html", |
||||||
|
"./src/**/*.{js,jsx,ts,tsx}" |
||||||
|
], |
||||||
|
theme: { |
||||||
|
extend: {}, |
||||||
|
}, |
||||||
|
plugins: [], |
||||||
|
} |
||||||
|
|
@ -0,0 +1,26 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", |
||||||
|
"target": "ES2020", |
||||||
|
"useDefineForClassFields": true, |
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"], |
||||||
|
"module": "ESNext", |
||||||
|
"skipLibCheck": true, |
||||||
|
|
||||||
|
/* Bundler mode */ |
||||||
|
"moduleResolution": "bundler", |
||||||
|
"allowImportingTsExtensions": true, |
||||||
|
"isolatedModules": true, |
||||||
|
"moduleDetection": "force", |
||||||
|
"noEmit": true, |
||||||
|
"jsx": "react-jsx", |
||||||
|
|
||||||
|
/* Linting */ |
||||||
|
"strict": true, |
||||||
|
"noUnusedLocals": true, |
||||||
|
"noUnusedParameters": true, |
||||||
|
"noFallthroughCasesInSwitch": true, |
||||||
|
"noUncheckedSideEffectImports": true |
||||||
|
}, |
||||||
|
"include": ["src"] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"files": [], |
||||||
|
"references": [ |
||||||
|
{ "path": "./tsconfig.app.json" }, |
||||||
|
{ "path": "./tsconfig.node.json" } |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", |
||||||
|
"target": "ES2022", |
||||||
|
"lib": ["ES2023"], |
||||||
|
"module": "ESNext", |
||||||
|
"skipLibCheck": true, |
||||||
|
|
||||||
|
/* Bundler mode */ |
||||||
|
"moduleResolution": "bundler", |
||||||
|
"allowImportingTsExtensions": true, |
||||||
|
"isolatedModules": true, |
||||||
|
"moduleDetection": "force", |
||||||
|
"noEmit": true, |
||||||
|
|
||||||
|
/* Linting */ |
||||||
|
"strict": true, |
||||||
|
"noUnusedLocals": true, |
||||||
|
"noUnusedParameters": true, |
||||||
|
"noFallthroughCasesInSwitch": true, |
||||||
|
"noUncheckedSideEffectImports": true |
||||||
|
}, |
||||||
|
"include": ["vite.config.ts"] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
import { defineConfig } from 'vite' |
||||||
|
import react from '@vitejs/plugin-react' |
||||||
|
|
||||||
|
// https://vite.dev/config/
|
||||||
|
export default defineConfig({ |
||||||
|
plugins: [react()], |
||||||
|
}) |
Loading…
Reference in new issue