A code experiment on creating a pdf viewer without dependencies. Not even React. It recreates basic component concepts in plain Typescript.
The viewer allows to load a PDF and:
- Next and previous page navigation.
- Add comments (sticky notes) at coordinates and page.
- Move comments.
- Select some of the comments on the page or on a sidebar.
- Hide selected or all comments .
- Export comments as standard file.
With Node installed, install dependencies with
npm installBuild and serve the project with
npm run build && npm run serveThis will make the project available at http://localhost:3000
We are not using any other libraries than PDF js dist to render pages as images:
PDF js dist(https://www.npmjs.com/package/pdfjs-dist)
This seemed to be the closest library for our usecase. It had some problems with typings, and the bundle is much bigger because of a worker option.
Because no JSX/React/x was the objective of the experiment, I reimplemented a very minimal component framework from scratch.
It consists of:
dom.tsto create htmlevent.tsto act as a central state management (like redux or Elm)component.tsto implement a base component class from which all components inherit
All the low-level pdf operations and "ugly bits" are in mypdfviewer.ts. Once the user has uploaded a file, the general UI is managed from our custom components.
Everything works similarly to a state machine, sending well-defined events, updating the state and rerendering everything.
I focused on the event management, since the component testing would be more integration testing.
npm run testFor the e2e test I have tested the adding and removing of components, including accross pages. To run the e2e tests with playwright, run:
npm run build && npm run serverAnd in a different terminal tab:
npm run e2eYou can also run it with the ui to see step by step interactions
npm run e2e_uiAnd check the report of the ran tests with
npm run e2e_reportWe can run format with:
npm run formattypechecks with
npm run checkand linters with
npm run lintTypedoc was used for documentation. The generated docs are included in the repo, but you can regenerate them by running:
npm run generate_docsLeft out for now. We have the export only.
An option needed for the library increased the bundle size by a lot. Explore how to remove it.
There are a couple of anys still left. While event.ts is type safe regarding the key, it is not regarding the payload.
A Docker image to run the project would be nice to:
- not need any specific Nodejs version
- Test new versions compatibility
- Easily run on CI/CD pipelines
Once supported, @scope could be implemented in component.ts to not need to pass the id in the styles string.
mozilla/standards-positions#472
:scope {
background-color: #4CAF50;
border: none;
color: white;
padding: 20px;
}
:scope:hover {
background-color: blue;
}
