frontend with build and publish ci
This commit is contained in:
parent
e5e066bdcc
commit
3afc775f62
|
@ -10,3 +10,4 @@ insert_final_newline = true
|
|||
|
||||
[*.yml]
|
||||
indent_style=space
|
||||
indent_size = 2
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
pipeline:
|
||||
deps:
|
||||
image: node:alpine
|
||||
commands:
|
||||
- cd frontend
|
||||
- npm install --save-dev
|
||||
eslint:
|
||||
image: node:alpine
|
||||
commands:
|
||||
- cd frontend
|
||||
- npm run lint
|
||||
group: build
|
||||
svelte:
|
||||
image: node:alpine
|
||||
commands:
|
||||
- cd frontend
|
||||
- npm run build
|
||||
docker build:
|
||||
image: plugins/docker
|
||||
settings:
|
||||
dry_run: true
|
||||
repo: git.koval.net/cyclane/game-algorithms/frontend
|
||||
tags: latest
|
||||
context: frontend
|
||||
dockerfile: frontend/Dockerfile
|
||||
when:
|
||||
branch:
|
||||
exclude: [main]
|
||||
path:
|
||||
include:
|
||||
- frontend/*
|
||||
- .woodpecker/frontend.yml
|
||||
docker build and publish:
|
||||
image: plugins/docker
|
||||
settings:
|
||||
registry: git.koval.net
|
||||
username: cyclane
|
||||
password:
|
||||
from_secret: DEPLOY_TOKEN
|
||||
repo: git.koval.net/cyclane/game-algorithms/frontend
|
||||
tags: latest
|
||||
context: frontend
|
||||
dockerfile: frontend/Dockerfile
|
||||
when:
|
||||
branch: main
|
||||
path:
|
||||
include:
|
||||
- frontend/*
|
||||
- .woodpecker/frontend.yml
|
|
@ -0,0 +1,13 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Ignore files for PNPM, NPM and YARN
|
||||
pnpm-lock.yaml
|
||||
package-lock.json
|
||||
yarn.lock
|
|
@ -0,0 +1,44 @@
|
|||
module.exports = {
|
||||
root: true,
|
||||
parser: "@typescript-eslint/parser",
|
||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:jsdoc/recommended"],
|
||||
plugins: ["svelte3", "@typescript-eslint", "jsdoc"],
|
||||
ignorePatterns: ["*.cjs"],
|
||||
overrides: [{ files: ["*.svelte"], processor: "svelte3/svelte3" }],
|
||||
settings: {
|
||||
"svelte3/typescript": () => require("typescript")
|
||||
},
|
||||
parserOptions: {
|
||||
sourceType: "module",
|
||||
ecmaVersion: 2020
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
es2017: true,
|
||||
node: true
|
||||
},
|
||||
rules: {
|
||||
semi: 2,
|
||||
"semi-spacing": ["error", {before: false, after: false}],
|
||||
"object-curly-spacing": ["error", "always"],
|
||||
"sort-imports": 2,
|
||||
indent: ["error", "tab"],
|
||||
"eol-last": 2,
|
||||
"max-len": ["error", {code: 120}],
|
||||
"prefer-const": 2,
|
||||
quotes: ["error", "double"],
|
||||
|
||||
"@typescript-eslint/no-explicit-any": 2,
|
||||
"@typescript-eslint/no-unused-vars": 2,
|
||||
|
||||
"jsdoc/require-description": 2,
|
||||
"jsdoc/require-jsdoc": 2,
|
||||
"jsdoc/require-param-description": 2,
|
||||
"jsdoc/require-param-name": 2,
|
||||
"jsdoc/require-param-type": 0,
|
||||
"jsdoc/require-returns": ["error", {forceReturnsWithAsync: true}],
|
||||
"jsdoc/require-returns-check": 2,
|
||||
"jsdoc/require-returns-description": 2,
|
||||
"jsdoc/require-returns-type": 0
|
||||
}
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
.DS_Store
|
||||
node_modules
|
||||
/build
|
||||
/.svelte-kit
|
||||
/package
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
|
@ -0,0 +1 @@
|
|||
engine-strict=true
|
|
@ -0,0 +1,12 @@
|
|||
FROM node:alpine
|
||||
|
||||
COPY build /app/build
|
||||
COPY package.json /app/package.json
|
||||
|
||||
HEALTHCHECK --interval=30s --retries=3 --start-period=10s --timeout=1s \
|
||||
CMD wget -q --tries=1 --spider http://localhost:3000/ || exit 1
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
WORKDIR /app
|
||||
ENTRYPOINT [ "node", "build" ]
|
|
@ -0,0 +1,38 @@
|
|||
# create-svelte
|
||||
|
||||
Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/master/packages/create-svelte).
|
||||
|
||||
## Creating a project
|
||||
|
||||
If you're seeing this, you've probably already done this step. Congrats!
|
||||
|
||||
```bash
|
||||
# create a new project in the current directory
|
||||
npm create svelte@latest
|
||||
|
||||
# create a new project in my-app
|
||||
npm create svelte@latest my-app
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
|
||||
# or start the server and open the app in a new browser tab
|
||||
npm run dev -- --open
|
||||
```
|
||||
|
||||
## Building
|
||||
|
||||
To create a production version of your app:
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
You can preview the production build with `npm run preview`.
|
||||
|
||||
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "frontend",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "vite dev",
|
||||
"build": "vite build",
|
||||
"package": "svelte-kit package",
|
||||
"preview": "vite preview",
|
||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
||||
"lint": "eslint .",
|
||||
"lint-fix": "eslint . --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-node": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"@typescript-eslint/eslint-plugin": "^5.27.0",
|
||||
"@typescript-eslint/parser": "^5.27.0",
|
||||
"carbon-components-svelte": "^0.67.7",
|
||||
"carbon-icons-svelte": "^11.2.0",
|
||||
"carbon-preprocess-svelte": "^0.9.1",
|
||||
"eslint": "^8.16.0",
|
||||
"eslint-plugin-jsdoc": "^39.3.4",
|
||||
"eslint-plugin-svelte3": "^4.0.0",
|
||||
"svelte": "^3.44.0",
|
||||
"svelte-check": "^2.7.1",
|
||||
"svelte-preprocess": "^4.10.6",
|
||||
"tslib": "^2.3.1",
|
||||
"typescript": "^4.7.4",
|
||||
"vite": "^3.0.0",
|
||||
"vite-plugin-wasm-pack": "0.1.11"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@game-algorithms/o-x-rust": "^0.0.9"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
// and what to do when importing types
|
||||
declare namespace App {
|
||||
// interface Locals {}
|
||||
// interface Platform {}
|
||||
// interface PrivateEnv {}
|
||||
// interface PublicEnv {}
|
||||
// interface Session {}
|
||||
// interface Stuff {}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<!DOCTYPE html>
|
||||
<html theme="g100" lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
%sveltekit.body%
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,8 @@
|
|||
<div></div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,10 @@
|
|||
<h1>○</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
text-align: center;
|
||||
font-size: 4rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,10 @@
|
|||
<h1>⨯</h1>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
text-align: center;
|
||||
font-size: 4rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,38 @@
|
|||
<script lang="ts">
|
||||
import "carbon-components-svelte/css/all.css";
|
||||
import {
|
||||
Content,
|
||||
Header,
|
||||
HeaderGlobalAction,
|
||||
HeaderNav,
|
||||
HeaderNavItem,
|
||||
HeaderUtilities,
|
||||
SkipToContent,
|
||||
Theme
|
||||
} from "carbon-components-svelte";
|
||||
import Moon from "carbon-icons-svelte/lib/Moon.svelte";
|
||||
import Sun from "carbon-icons-svelte/lib/Sun.svelte";
|
||||
|
||||
let dark = true;
|
||||
</script>
|
||||
|
||||
<Theme
|
||||
theme={dark ? "g100" : "white"}
|
||||
on:update={update => dark = update.detail.theme === "g100"}
|
||||
persist persistKey="__carbon-theme"
|
||||
/>
|
||||
|
||||
<Header company="Cyclane" platformName="Game Algorithms">
|
||||
<svelte:fragment slot="skip-to-content">
|
||||
<SkipToContent />
|
||||
</svelte:fragment>
|
||||
<HeaderNav>
|
||||
<HeaderNavItem href="/" text="About"/>
|
||||
<HeaderNavItem href="/o-x" text="Noughts & Crosses"/>
|
||||
</HeaderNav>
|
||||
<HeaderUtilities>
|
||||
<HeaderGlobalAction icon={dark ? Moon : Sun} on:click={() => dark = !dark}/>
|
||||
</HeaderUtilities>
|
||||
</Header>
|
||||
|
||||
<Content><slot/></Content>
|
|
@ -0,0 +1,37 @@
|
|||
<script lang="ts">
|
||||
import { Column, Grid, Link, Row } from "carbon-components-svelte";
|
||||
</script>
|
||||
|
||||
<Grid>
|
||||
<Row>
|
||||
<Column>
|
||||
<h1>Game Algorithms</h1>
|
||||
<img
|
||||
class="link"
|
||||
alt="CI badge"
|
||||
src="https://woodpecker.koval.net/api/badges/cyclane/game-algorithms/status.svg"
|
||||
on:click={() => window.location.href = "https://woodpecker.koval.net/cyclane/game-algorithms"}
|
||||
/>
|
||||
|
||||
<p>
|
||||
This is a learning project for various board-game alogrithms.
|
||||
</p>
|
||||
<p>
|
||||
Visit the <Link inline href="https://git.koval.net/cyclane/game-algorithms">Git repo</Link> for source code.
|
||||
</p>
|
||||
</Column>
|
||||
</Row>
|
||||
</Grid>
|
||||
|
||||
<style>
|
||||
h1 {
|
||||
margin-bottom: var(--cds-layout-01);
|
||||
}
|
||||
p {
|
||||
margin-top: var(--cds-layout-01);
|
||||
margin-bottom: var(--cds-layout-01);
|
||||
}
|
||||
.link {
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,280 @@
|
|||
<script lang="ts">
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
DataTable,
|
||||
Grid,
|
||||
ListItem,
|
||||
RadioButton,
|
||||
RadioButtonGroup,
|
||||
Row,
|
||||
Toggle,
|
||||
UnorderedList
|
||||
} from "carbon-components-svelte";
|
||||
import wasmInit, { count_empty, find_winner, get_score, predict } from "@game-algorithms/o-x-rust";
|
||||
import OXNoneIcon from "$lib/components/OXNoneIcon.svelte";
|
||||
import OXOIcon from "$lib/components/OXOIcon.svelte";
|
||||
import OXXIcon from "$lib/components/OXXIcon.svelte";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let board: number[][] = [];
|
||||
for (let i = 0;i < 3;i++) {
|
||||
board.push([0, 0, 0]);
|
||||
}
|
||||
|
||||
let turn = -1;
|
||||
let playAs = "X";
|
||||
let algorithm = "mm+d";
|
||||
let human = 0;
|
||||
let bot = 0;
|
||||
let loaded = false;
|
||||
let showPreviousScores = false;
|
||||
let showCurrentScores = false;
|
||||
let showScoresFor = "human";
|
||||
let status = "Press 'Start' to play";
|
||||
// step: cell: [human, bot]
|
||||
let scores: [number | null, number | null][][] = [];
|
||||
|
||||
onMount(async () => {
|
||||
await wasmInit();
|
||||
loaded = true;
|
||||
});
|
||||
|
||||
/**
|
||||
* Complete a turn logic
|
||||
*/
|
||||
function completeTurn() {
|
||||
const convertedBoard = Uint8Array.from(board.flat());
|
||||
scores = [...scores, getBoardScore(board, human, bot, algorithm)];
|
||||
const winner = find_winner(convertedBoard);
|
||||
if (winner !== 0 || count_empty(convertedBoard) === 0) {
|
||||
turn = -1;
|
||||
switch (winner) {
|
||||
case 0:
|
||||
status = "You drew!";
|
||||
break;
|
||||
case human:
|
||||
status = "You won!";
|
||||
break;
|
||||
case bot:
|
||||
status = `The ${algorithm} algorithm defeated you!`;
|
||||
break;
|
||||
default:
|
||||
status = "How did we get here?";
|
||||
break;
|
||||
}
|
||||
alert(status);
|
||||
return;
|
||||
}
|
||||
turn %= 2;
|
||||
turn += 1;
|
||||
if (turn === human) {
|
||||
status = "Your turn!";
|
||||
} else {
|
||||
status = "Algorithm's turn!";
|
||||
const p = predict(bot, human, bot === 1, convertedBoard, algorithm);
|
||||
board[Math.floor(p / 3)][p % 3] = bot;
|
||||
completeTurn();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the scores for all possible moves on the board for each player
|
||||
*
|
||||
* @param board The board
|
||||
* @param human The human player ID
|
||||
* @param bot The bot player ID
|
||||
* @param algorithm The algorithm to use for scoring
|
||||
* @returns The scores for the moves for each cell and player
|
||||
*/
|
||||
function getBoardScore(
|
||||
board: number[][],
|
||||
human: number,
|
||||
bot: number,
|
||||
algorithm: string
|
||||
): [number | null, number | null][] {
|
||||
return board.flat().map((v, i) => {
|
||||
if (v === 0) {
|
||||
const humanCopy = board.flat();
|
||||
humanCopy[i] = human;
|
||||
const hUint8Array = Uint8Array.from(humanCopy);
|
||||
const botCopy = board.flat();
|
||||
botCopy[i] = bot;
|
||||
const bUint8Array = Uint8Array.from(humanCopy);
|
||||
return [
|
||||
get_score(human, bot, human === 1, hUint8Array, algorithm),
|
||||
get_score(bot, human, bot === 1, bUint8Array, algorithm)
|
||||
];
|
||||
} else {
|
||||
return [null, null];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to add up to <dp> decimal places to a number
|
||||
*
|
||||
* @param n Number
|
||||
* @param dp Maximum decimal places
|
||||
* @returns String formated number
|
||||
*/
|
||||
function toFixedOrLess(n: number, dp: number) {
|
||||
const f = n.toFixed(dp);
|
||||
const [u, d] = f.split(".");
|
||||
const minD = d.slice(0, d.indexOf("0"));
|
||||
if (minD.length === 0) {
|
||||
return u;
|
||||
}
|
||||
return u + "." + minD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a table row from an array of scores
|
||||
*
|
||||
* @param player Player to get scores for
|
||||
* @param moveOverride Override the move key value
|
||||
* @returns The generated table row
|
||||
*/
|
||||
function scoreToRows(player: string, moveOverride?: string) {
|
||||
return (score: [number | null, number | null][], i: number) => {
|
||||
const rowScores: Record<string, string> = {};
|
||||
for (let cell = 0;cell < 9;cell++) {
|
||||
const s = score[cell][player === "human" ? 0 : 1];
|
||||
rowScores[cell.toString()] = s === null ? "-" : toFixedOrLess(s, 3);
|
||||
}
|
||||
return {
|
||||
id: i,
|
||||
move: moveOverride || i + 1,
|
||||
...rowScores
|
||||
};
|
||||
};
|
||||
}
|
||||
</script>
|
||||
|
||||
<Grid>
|
||||
<Row>
|
||||
<Column>
|
||||
<h1>Noughts and Crosses</h1>
|
||||
<p>
|
||||
This is a noughts and crosses bot using various algorithms.
|
||||
</p>
|
||||
<UnorderedList>
|
||||
<ListItem>sa: score adding without optimizations</ListItem>
|
||||
<ListItem>sa+rd: score adding with ratio optimization including draw (score between win and loose)</ListItem>
|
||||
<ListItem>sa+r-d: score adding with ratio optimization not including draw (draw = loss)</ListItem>
|
||||
<ListItem>mm: minimax</ListItem>
|
||||
<ListItem>mm+d: minimax with depth</ListItem>
|
||||
</UnorderedList>
|
||||
<div class="selection">
|
||||
<RadioButtonGroup disabled={turn !== -1} legendText="Algorithms" bind:selected={algorithm}>
|
||||
<RadioButton labelText="sa" value="sa" />
|
||||
<RadioButton labelText="sa+rd" value="sa+rd" />
|
||||
<RadioButton labelText="sa+r-d" value="sa+r-d" />
|
||||
<RadioButton labelText="mm" value="mm" />
|
||||
<RadioButton labelText="mm+d" value="mm+d" />
|
||||
</RadioButtonGroup>
|
||||
</div>
|
||||
<div class="selection">
|
||||
<RadioButtonGroup disabled={turn !== -1} legendText="Play as" bind:selected={playAs}>
|
||||
<RadioButton labelText="Noughts" value="O" />
|
||||
<RadioButton labelText="Crosses" value="X" />
|
||||
</RadioButtonGroup>
|
||||
</div>
|
||||
<Button disabled={!loaded || turn !== -1} on:click={() => {
|
||||
board = [];
|
||||
scores = [];
|
||||
for (let i = 0;i < 3;i++) {
|
||||
board.push([0, 0, 0]);
|
||||
}
|
||||
turn = 2;
|
||||
human = Number(playAs === "O") + 1;
|
||||
bot = human % 2 + 1;
|
||||
completeTurn();
|
||||
}}>Start</Button>
|
||||
</Column>
|
||||
</Row>
|
||||
<hr/>
|
||||
<Row>
|
||||
<Column>
|
||||
<h2>Board</h2>
|
||||
<p>{status}</p>
|
||||
{#if loaded}
|
||||
<Grid>
|
||||
{#each board as row, r}
|
||||
<Row>
|
||||
{#each row as col, c}
|
||||
<Column sm={.1} style="border: 1px solid white;">
|
||||
<Button
|
||||
kind="tertiary"
|
||||
iconDescription={col === 0 ? "Available" : col === 1 ? "Cross" : "Nought"}
|
||||
icon={col === 0 ? OXNoneIcon : col === 1 ? OXXIcon : OXOIcon}
|
||||
disabled={board[r][c] !== 0 || turn !== human}
|
||||
on:click={() => {
|
||||
board[r][c] = human;
|
||||
completeTurn();
|
||||
console.log(scores);
|
||||
}}
|
||||
/>
|
||||
</Column>
|
||||
{/each}
|
||||
</Row>
|
||||
{/each}
|
||||
</Grid>
|
||||
{:else}
|
||||
<h3>Loading...</h3>
|
||||
{/if}
|
||||
</Column>
|
||||
</Row>
|
||||
<hr/>
|
||||
<Row>
|
||||
<Column>
|
||||
<h2>Scores</h2>
|
||||
<p>
|
||||
View scores for each potential move here.
|
||||
Cells are numbered from 1 to 9 going left-to-right, top-to-bottom.
|
||||
The table headers show the cell numbers.
|
||||
</p>
|
||||
<Toggle labelText="Show previous scores" bind:toggled={showPreviousScores}/>
|
||||
<Toggle labelText="Show current scores" bind:toggled={showCurrentScores}/>
|
||||
<div class="selection">
|
||||
<RadioButtonGroup legendText="Shows scores for" bind:selected={showScoresFor}>
|
||||
<RadioButton labelText="You" value="human" />
|
||||
<RadioButton labelText="The algorithm" value="bot" />
|
||||
</RadioButtonGroup>
|
||||
</div>
|
||||
{#if showPreviousScores || showCurrentScores}
|
||||
<DataTable headers={[
|
||||
{
|
||||
key: "move",
|
||||
value: "Move"
|
||||
},
|
||||
...board.flat().map((_, c) => {
|
||||
return {
|
||||
key: c.toString(),
|
||||
value: (c + 1).toString()
|
||||
};
|
||||
})
|
||||
]}
|
||||
rows={[
|
||||
...(showPreviousScores ?
|
||||
scores.slice(0, -1).map(scoreToRows(showScoresFor)) : []
|
||||
),
|
||||
...(showCurrentScores && scores.length !== 0 ?
|
||||
[scoreToRows(showScoresFor, "Now")(scores.slice(-1)[0], scores.length)] : []
|
||||
)
|
||||
]}
|
||||
/>
|
||||
{/if}
|
||||
</Column>
|
||||
</Row>
|
||||
</Grid>
|
||||
|
||||
<style>
|
||||
h1, h2, h3 {
|
||||
margin-bottom: var(--cds-layout-01);
|
||||
}
|
||||
p, .selection {
|
||||
margin-top: var(--cds-layout-01);
|
||||
margin-bottom: var(--cds-layout-01);
|
||||
}
|
||||
</style>
|
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -0,0 +1,19 @@
|
|||
import adapter from "@sveltejs/adapter-node";
|
||||
import { optimizeImports } from "carbon-preprocess-svelte";
|
||||
import preprocess from "svelte-preprocess";
|
||||
|
||||
/** @type {import("@sveltejs/kit").Config} */
|
||||
const config = {
|
||||
// Consult https://github.com/sveltejs/svelte-preprocess
|
||||
// for more information about preprocessors
|
||||
preprocess: [
|
||||
preprocess(),
|
||||
optimizeImports(),
|
||||
],
|
||||
|
||||
kit: {
|
||||
adapter: adapter()
|
||||
}
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"skipLibCheck": true,
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"moduleResolution": "Node"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import wasmPack from "vite-plugin-wasm-pack";
|
||||
|
||||
const config = {
|
||||
plugins: [
|
||||
sveltekit(),
|
||||
wasmPack([], ["@game-algorithms/o-x-rust"])
|
||||
]
|
||||
};
|
||||
|
||||
export default config;
|
Loading…
Reference in New Issue