finish web demo

main
Ziyang Hu 2 years ago
parent 3536863622
commit abe6866065

@ -551,7 +551,7 @@ impl Display for AlgoRuleArg {
f.debug_list().entries(bindings).finish()?;
}
AlgoRuleArg::NamedStored { name, bindings, .. } => {
write!(f, ":")?;
write!(f, "*")?;
let mut sf = f.debug_struct(name);
for (k, v) in bindings {
sf.field(k, v);
@ -1090,7 +1090,7 @@ impl Display for InputAtom {
InputAtom::NamedFieldRelation {
inner: InputNamedFieldRelationApplyAtom { name, args, .. },
} => {
f.write_str(":")?;
f.write_str("*")?;
let mut sf = f.debug_struct(name);
for (k, v) in args {
sf.field(k, v);

@ -29,6 +29,6 @@ wee_alloc = { version = "0.4.5", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.13"
[profile.release]
# Tell `rustc` to optimize for small code size.
opt-level = "s"
#[profile.release]
## Tell `rustc` to optimize for small code size.
#opt-level = "s"

@ -0,0 +1,3 @@
#!/usr/bin/env bash
CARGO_PROFILE_RELEASE_LTO=fat wasm-pack build --target web --release

@ -1,32 +0,0 @@
/*
* Copyright 2022, The Cozo Project Authors.
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#!/usr/bin/env node
const { spawn } = require("child_process");
const fs = require("fs");
let folderName = '.';
if (process.argv.length >= 3) {
folderName = process.argv[2];
if (!fs.existsSync(folderName)) {
fs.mkdirSync(folderName);
}
}
const clone = spawn("git", ["clone", "https://github.com/rustwasm/create-wasm-app.git", folderName]);
clone.on("close", code => {
if (code !== 0) {
console.error("cloning the template failed!")
process.exit(code);
} else {
console.log("🦀 Rust + 🕸 Wasm = ❤");
}
});

@ -1,2 +0,0 @@
node_modules
dist

@ -1,5 +0,0 @@
language: node_js
node_js: "10"
script:
- ./node_modules/.bin/webpack

@ -1,67 +0,0 @@
<div align="center">
<h1><code>create-wasm-app</code></h1>
<strong>An <code>npm init</code> template for kick starting a project that uses NPM packages containing Rust-generated WebAssembly and bundles them with Webpack.</strong>
<p>
<a href="https://travis-ci.org/rustwasm/create-wasm-app"><img src="https://img.shields.io/travis/rustwasm/create-wasm-app.svg?style=flat-square" alt="Build Status" /></a>
</p>
<h3>
<a href="#usage">Usage</a>
<span> | </span>
<a href="https://discordapp.com/channels/442252698964721669/443151097398296587">Chat</a>
</h3>
<sub>Built with 🦀🕸 by <a href="https://rustwasm.github.io/">The Rust and WebAssembly Working Group</a></sub>
</div>
## About
This template is designed for depending on NPM packages that contain
Rust-generated WebAssembly and using them to create a Website.
* Want to create an NPM package with Rust and WebAssembly? [Check out
`wasm-pack-template`.](https://github.com/rustwasm/wasm-pack-template)
* Want to make a monorepo-style Website without publishing to NPM? Check out
[`rust-webpack-template`](https://github.com/rustwasm/rust-webpack-template)
and/or
[`rust-parcel-template`](https://github.com/rustwasm/rust-parcel-template).
## 🚴 Usage
```
npm init wasm-app
```
## 🔋 Batteries Included
- `.gitignore`: ignores `node_modules`
- `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you
- `README.md`: the file you are reading now!
- `index.html`: a bare bones html document that includes the webpack bundle
- `index.js`: example js file with a comment showing how to import and use a wasm pkg
- `package.json` and `package-lock.json`:
- pulls in devDependencies for using webpack:
- [`webpack`](https://www.npmjs.com/package/webpack)
- [`webpack-cli`](https://www.npmjs.com/package/webpack-cli)
- [`webpack-dev-server`](https://www.npmjs.com/package/webpack-dev-server)
- defines a `start` script to run `webpack-dev-server`
- `webpack.config.js`: configuration file for bundling your js with webpack
## License
Licensed under either of
* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.

@ -1,13 +0,0 @@
/*
* Copyright 2022, The Cozo Project Authors.
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
// A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again.
import("./index.js")
.catch(e => console.error("Error importing `index.js`:", e));

@ -1,19 +0,0 @@
<!--
~ Copyright 2022, The Cozo Project Authors.
~
~ This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
~ If a copy of the MPL was not distributed with this file,
~ You can obtain one at https://mozilla.org/MPL/2.0/.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Hello wasm-pack!</title>
</head>
<body>
<noscript>This page contains webassembly and javascript content, please enable javascript in your browser.</noscript>
<script src="./bootstrap.js"></script>
</body>
</html>

@ -1,70 +0,0 @@
/*
* Copyright 2022, The Cozo Project Authors.
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
import {CozoDb} from "cozo-lib-wasm";
const db = CozoDb.new();
console.log(db);
function query(script, params) {
const result = JSON.parse(db.run(script, params || ''));
console.log(result);
if (result.ok) {
const headers = result.headers || [];
const rows = result.rows.map(row => {
let ret = {};
for (let i = 0; i < row.length; ++i) {
ret[headers[i] || `(${i})`] = row[i];
}
return ret
});
console.table(rows)
} else {
console.error(result.display || result.message)
}
}
query(`
?[loving, loved] <- [['alice', 'eve'],
['bob', 'alice'],
['eve', 'alice'],
['eve', 'bob'],
['eve', 'charlie'],
['charlie', 'eve'],
['david', 'george'],
['george', 'george']]
:replace love {loving, loved}
`);
query(`
alice_love_chain[person] := *love['alice', person]
alice_love_chain[person] := alice_love_chain[in_person], *love[in_person, person]
?[chained] := alice_love_chain[chained]
`)
query(`
?[person, page_rank] <~ PageRank(*love[])
:order -page_rank
`);
query(`
?[loved_by_e_not_b] := *love['eve', loved_by_e_not_b], not *love['bob', loved_by_e_not_b]
`);
query(`
?[] <- [[parse_timestamp(format_timestamp(now(), 'Asia/Shanghai')),]]
`);
query(`
?[] <- [[rand_uuid_v1()]]
`);

@ -1,39 +0,0 @@
{
"name": "create-wasm-app",
"version": "0.1.0",
"description": "create an app to consume rust-generated wasm packages",
"main": "index.js",
"bin": {
"create-wasm-app": ".bin/create-wasm-app.js"
},
"scripts": {
"build": "webpack --config webpack.config.js",
"start": "webpack-dev-server"
},
"repository": {
"type": "git",
"url": "git+https://github.com/rustwasm/create-wasm-app.git"
},
"keywords": [
"webassembly",
"wasm",
"rust",
"webpack"
],
"author": "Ashley Williams <ashley666ashley@gmail.com>",
"license": "MPL-2.0",
"bugs": {
"url": "https://github.com/rustwasm/create-wasm-app/issues"
},
"homepage": "https://github.com/rustwasm/create-wasm-app#readme",
"devDependencies": {
"hello-wasm-pack": "^0.1.0",
"webpack": "^4.29.3",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.5",
"copy-webpack-plugin": "^5.0.0"
},
"dependencies": {
"cozo-lib-wasm": "file:../pkg"
}
}

@ -1,22 +0,0 @@
/*
* Copyright 2022, The Cozo Project Authors.
*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file,
* You can obtain one at https://mozilla.org/MPL/2.0/.
*/
const CopyWebpackPlugin = require("copy-webpack-plugin");
const path = require('path');
module.exports = {
entry: "./bootstrap.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bootstrap.js",
},
mode: "development",
plugins: [
new CopyWebpackPlugin(['index.html'])
],
};

File diff suppressed because it is too large Load Diff

@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

@ -0,0 +1,70 @@
# Getting Started with Create React App
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
## Available Scripts
In the project directory, you can run:
### `npm start`
Runs the app in the development mode.\
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
The page will reload when you make changes.\
You may also see any lint errors in the console.
### `npm test`
Launches the test runner in the interactive watch mode.\
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
### `npm run build`
Builds the app for production to the `build` folder.\
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.\
Your app is ready to be deployed!
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
### `npm run eject`
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
## Learn More
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
To learn React, check out the [React documentation](https://reactjs.org/).
### Code Splitting
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
### Analyzing the Bundle Size
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
### Making a Progressive Web App
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
### Advanced Configuration
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
### Deployment
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
### `npm run build` fails to minify
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)

@ -0,0 +1,8 @@
#!/usr/bin/env bash
rm -fr node_modules
rm -fr build
yarn
yarn build
rm -fr ~/cozodb_site/wasm-demo/
mv build ~/cozodb_site/wasm-demo

@ -0,0 +1,43 @@
{
"name": "cozo-web",
"version": "0.1.0",
"private": true,
"dependencies": {
"@blueprintjs/core": "^4.12.0",
"@blueprintjs/table": "^4.7.9",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"ansicolor": "^1.1.100",
"cozo-lib-wasm": "file:../pkg",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"homepage": "."
}

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Cozo in WASM</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

@ -0,0 +1,21 @@
@import "~normalize.css";
@import "~@blueprintjs/core/lib/css/blueprint.css";
@import "~@blueprintjs/icons/lib/css/blueprint-icons.css";
@import "~@blueprintjs/table/lib/css/table.css";
#error-message, #other-results {
padding: 10px;
overflow: scroll;
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
font-size: 90%;
}
#query-box, #params-box {
font-family: Menlo, Monaco, Consolas, "Courier New", monospace;
font-size: 100%;
min-height: 200px;
max-height: 40vh;
min-width: 200px;
}
#welcome {
padding: 15px;
}

@ -0,0 +1,206 @@
import './App.css';
import {Button, Intent, Tag, TextArea} from "@blueprintjs/core";
import {Cell, Column, Table2} from "@blueprintjs/table";
import React, {useEffect, useState} from "react";
import init, {CozoDb} from "cozo-lib-wasm";
import {parse} from "ansicolor";
function App() {
const [db, setDb] = useState(null);
const [params, setParams] = useState('{\n\n}');
const [showParams, setShowParams] = useState(false);
const [queryText, setQueryText] = useState('');
const [inProgress, setInProgress] = useState(false);
const [statusMessage, setStatusMessage] = useState('');
const [errorMessage, setErrorMessage] = useState([]);
const [queryResults, setQueryResults] = useState(null);
useEffect(() => {
init().then(() => {
let db = CozoDb.new();
setDb(db);
})
}, []);
const renderCell = (colIdx) => (rowIdx) => <Cell>
{displayValue(queryResults.rows[rowIdx][colIdx])}
</Cell>
function handleKeyDown(e) {
if (e.key === 'Enter' && e.shiftKey) {
e.preventDefault();
e.stopPropagation();
handleQuery();
}
if (e.key === 'Tab' && !e.shiftKey) {
e.preventDefault();
e.stopPropagation();
typeInTextarea(' ');
}
}
function typeInTextarea(newText, el = document.activeElement) {
const [start, end] = [el.selectionStart, el.selectionEnd];
el.setRangeText(newText, start, end, 'end');
}
function displayValue(v) {
if (typeof v === 'string') {
return v
} else {
return <span style={{color: "#184A90"}}>{JSON.stringify(v)}</span>
}
}
async function handleQuery() {
if (!db) {
setInProgress(false);
setErrorMessage([]);
setStatusMessage(['database not ready']);
setQueryResults(null);
return;
}
const query = queryText.trim();
if (query) {
setInProgress(true);
setErrorMessage([]);
setStatusMessage('');
setQueryResults(null);
try {
const t0 = performance.now();
const res_str = db.run(query, params);
const t1 = performance.now();
const res = JSON.parse(res_str);
if (res.ok) {
setStatusMessage(`finished with ${res.rows.length} rows in ${(t1 - t0).toFixed(2)}ms`);
if (!res.headers) {
res.headers = [];
if (res.rows.length) {
for (let i = 0; i < res.rows[0].length; i++) {
res.headers.push('' + i);
}
}
}
} else {
setStatusMessage(`finished with errors`);
if (res.display) {
const messages = parse(res.display);
setErrorMessage(messages.spans);
} else {
setErrorMessage([res.message]);
}
}
setQueryResults(res);
} catch (e) {
setStatusMessage(`query failed`);
setErrorMessage(['' + e]);
} finally {
setInProgress(false);
}
}
}
return (
<div style={{width: "100vw", height: "100vh", display: 'flex', flexDirection: 'column'}}>
<div style={{padding: 10}}>
<div style={{display: 'flex'}}>
<TextArea
autoFocus
placeholder="Type query, SHIFT + Enter to run"
id="query-box"
className="bp4-fill"
growVertically={true}
large={true}
intent={Intent.PRIMARY}
onChange={e => setQueryText(e.target.value)}
onKeyDown={handleKeyDown}
value={queryText}
/>
{showParams && <TextArea
id="params-box"
style={{marginLeft: 5}}
placeholder="Your params (a JSON map)"
large={true}
onChange={e => setParams(e.target.value)}
onKeyDown={handleKeyDown}
value={params}
/>}
</div>
<div/>
<div style={{paddingTop: 10, display: 'flex', flexDirection: 'row'}}>
<Button text={db ? "Run script" : "Loading Cozo library, please wait ..."}
onClick={() => handleQuery()}
disabled={!db || inProgress}
intent={Intent.PRIMARY}
/>
&nbsp;
<Button onClick={() => {
setShowParams(!showParams)
}}>{showParams ? 'Hide' : 'Show'} params</Button>
<div style={{marginLeft: 10, marginTop: 5}}>
{statusMessage ? <Tag intent={errorMessage.length ? Intent.DANGER : Intent.SUCCESS} minimal>
{statusMessage}
</Tag> : null}
</div>
</div>
</div>
{errorMessage.length ? <pre id="error-message">
{errorMessage.map((item, id) => {
if (typeof item === 'string') {
return <span key={id}>{item}</span>
} else {
let styles = {};
if (item.css) {
styles.color = item.css.replace('color:', '').replace(';', '');
}
return <span key={id} style={styles}>{item.text}</span>
}
})}
</pre> : null}
{queryResults ? (queryResults.rows && queryResults.headers ?
<Table2
numRows={queryResults.rows.length}
>
{queryResults.headers.map((n, idx) => <Column
name={n}
key={idx}
cellRenderer={renderCell(idx)}
/>)}
</Table2> : null) : null}
{!(queryResults || errorMessage.length) && <div id="welcome">
<p>
This is the demo page for Cozo running in your browser as
an <a href="https://webassembly.org/">Web assembly</a> module.
</p>
<p>
All computation is done within your browser. There is no backend, nor any outgoing requests.
</p>
<p>
Please refer to the <a href="https://github.com/cozodb/cozo/">project homepage</a> for
more information about the Cozo database.
</p>
<h2>Not sure what to run? Click/touch <a onClick={() => {
setQueryText(`love[loving, loved] <- [['alice', 'eve'],
['bob', 'alice'],
['eve', 'alice'],
['eve', 'bob'],
['eve', 'charlie'],
['charlie', 'eve'],
['david', 'george'],
['george', 'george']]
?[person, page_rank] <~ PageRank(love[])`)
}}>HERE</a> ...</h2>
<p>
... and run the script, to compute the <a href="https://www.wikiwand.com/en/PageRank">PageRank</a> of
a hypothetical love triangle.
</p>
</div>}
</div>
);
}
export default App;

@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

@ -0,0 +1,13 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

@ -0,0 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

@ -0,0 +1,13 @@
const reportWebVitals = onPerfEntry => {
if (onPerfEntry && onPerfEntry instanceof Function) {
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(onPerfEntry);
getFID(onPerfEntry);
getFCP(onPerfEntry);
getLCP(onPerfEntry);
getTTFB(onPerfEntry);
});
}
};
export default reportWebVitals;

@ -0,0 +1,5 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save