This project hosts a Comments React component that stores components locally using IndexedDB.
🚨 To save time, a deployed version is accessible at https://shff.github.io/9f57568ea/.
The main code of the challenge can be observed in the src/components/Comments folder and src/hooks.
The challenge text did not specify whether it wanted a component in a reusable Node Module Library or inside a full app. I decided to create a full app to demonstrate the component in action, PWA caching support and broadcasting between tabs.
The project looks big, but the heavy lifting was done by Vite and by my personal template that adds linting, formatting, testing and precommit hooks. 99% of the time was spent creating components and tests.
After it was done I spent another hour crating tests to get 100% coverage. The only difficult part was testing the IndexedDB logic, but I managed to do it by mocking the IndexedDB API.
I've been using Tailwind for a while now and I'm really enjoying it. Before that I was using Tachyons, another helper-first CSS library.
The comments are stored locally using IndexedDB. This allows the comments to persist even after the page is reloaded, and even if the user closes the browser and opens it again. This is done with native IndexedDB code, without the need for any additional libraries.
We're using a custom hook to handle the IndexedDB logic. We use a custom hook to take advantage of hook composition. State is synced using useState inside our custom hook, so there's no need for the outer component to manage state by itself. It is almost as simple as using useState in a regular component.
const { data, reload, add } = useIndexedDB<Comment>("DB1", "Comments");
<button onClick={() => add({ text: "Hello, World!" })}>Say hello</button>
{data.map((comment) => (
<div key={comment.id}>{comment.text}</div>
))}We use the BroadcastChannel feature to take care of broadcasting changes in comments to all tabs open in the same browser. This way, if the user opens the same page in multiple tabs, the comments will be synchronized between them. We don't broadcast to the same tab that originated the change, to avoid infinite loops.
We also use a hook for this feature. It uses a syntax similar to useEffect, where you pass a callback that will be called in other tabs when the dependencies on the third parameter change.
useBroadcast("comments", () => alert("Comments updated elsewhere!"), [localComments]);This project has partial PWA support. It has a service worker that caches the assets and the page itself. This way, the user can access the page even when offline.
The PWA support is available thanks to Vite's PWA plugin. The service worker is generated automatically when you build the project. Check vite.config.ts for more information.
We have end-to-end tests using Playwright. These tests cover the main features of the project, such as adding and deleting comments, persisting changes and broadcasting changes to other tabs.
We have a test suite that covers the main features of the project. We have 100% coverage on the client code.
This is a Node.js project. Make sure you have Node.js installed on your machine. We recommend using NVM to manage your Node.js versions. Check the installation instructions on the NVM repository.
For package manage, we use Yarn. To download the dependencies, run:
yarnWe use Vite for development. To run the project in development mode, run:
yarn devThe project should be running on http://localhost:5173 or the next available port.
To build the project, run:
yarn buildThe project should be built in the dist folder.
This project uses Vitest to run unit tests.
To execute the test sute, run:
yarn testTo run end-to-end tests, run:
yarn test:e2eWe use ESLint and Prettier to lint and format the code. To run the linter, run:
yarn lintTo run the formatter, run:
yarn formatWe also use simple-git-hooks and lint-staged to run the linter and formatter before committing. Git hooks should be installed automatically when you run yarn for the first time, but if you have any issues, you can install them manually by running:
yarn simple-git-hooks