Skip to content

Commit

Permalink
Merge pull request #12 from transcom/b-21230-resolve-dependencies
Browse files Browse the repository at this point in the history
B 21230 resolve dependencies
  • Loading branch information
cameroncaci authored Nov 20, 2024
2 parents 91e50f1 + ac31f65 commit 7c3da43
Show file tree
Hide file tree
Showing 15 changed files with 188 additions and 65 deletions.
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
# Table of contents
- [Table of contents](#table-of-contents)
- [react-file-viewer](#react-file-viewer)
- [Supported file formats:](#supported-file-formats)
- [Usage](#usage)
- [Development](#development)
- [To start demo app](#to-start-demo-app)
- [Testing](#testing)
- [To run the linter](#to-run-the-linter)
- [Extending the file viewer](#extending-the-file-viewer)
- [Viewing local changes in a secondary repo](#viewing-local-changes-in-a-secondary-repo)
- [Testing locally against the mymove application](#testing-locally-against-the-mymove-application)
- [Roadmap](#roadmap)


# react-file-viewer

Extendable file viewer for web
Expand Down Expand Up @@ -138,6 +153,22 @@ If you are working on a feature branch and need to see changes introduced in tha

`"@trussworks/react-file-viewer": "git+https://github.com/trussworks react-file-viewer"`

### Testing locally against the mymove application
Testing locally against the mymove application can be done via yarn link, but for the purpose of being thorough it is recommended to manually test against the `/dist/` output. This verifies the webpack is successfully compiling/transpiling and that the mymove application is successfully serving chunks.

TODO: ENHANCE ME (This is supposed to work, but it doesn't. Fallback is still `rm -rf node_modules && yarn install && ./scripts/copy-react-file-viewer && make client_run`)
1. [OPTIONAL] Within this repository, navigate to `webpack.config.js`. This is the production webpack.
1. Find where ` plugins: [new BundleAnalyzerPlugin({ analyzerMode: 'disabled' })]` is located and remove/enable the analyzerMode attribute
2. This makes it so you can preview the chunks
2. Within this repository, run `yarn build`, it should output new files to `/dist/`
3. Within the [MyMove repository](https://github.com/transcom/mymove) update `package.json` and set `"@transcom/react-file-viewer"` to point to the local location of this repository: Such as `"file:../react-file-viewer"`
4. Within MyMove, run `yarn upgrade @transcom/react-file-viewer`
5. Within MyMove, run `./scripts/copy-react-file-viewer`

You should now successfully be testing the webpack build of react-file-viewer against MyMove. Each time you adjust react-file-viewer, repeat steps 2, 4, and 5 to reflect within MyMove.

The benefit of working this way over yarn link is that we can properly simulate MyMove serving the chunks from its `./scripts/copy-react-file-viewer`.

## Roadmap

- [ ] Remove ignored linting rules and fix them
Expand Down
1 change: 1 addition & 0 deletions dist/13.chunk.js

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion dist/332.index.js

This file was deleted.

2 changes: 0 additions & 2 deletions dist/352.index.js

This file was deleted.

4 changes: 2 additions & 2 deletions dist/560.index.js → dist/840.index.js

Large diffs are not rendered by default.

File renamed without changes.
18 changes: 18 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Html Webpack Plugin:
<pre>
Error: The loader "/Users/cameron.jewell_cn/Projects/react-file-viewer/node_modules/html-webpack-plugin/lib/loader.js!/Users/cameron.jewell_cn/Projects/react-file-viewer/node_modules/html-webpack-plugin/default_index.ejs" didn't return html.

- index.js:323 HtmlWebpackPlugin.evaluateCompilationResult
[react-file-viewer]/[html-webpack-plugin]/index.js:323:24

- index.js:230
[react-file-viewer]/[html-webpack-plugin]/index.js:230:22

- task_queues:95 process.processTicksAndRejections
node:internal/process/task_queues:95:5

- async Promise.all

- async Promise.all

</pre>
2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions dist/pdfjs-dist-webpack.chunk.js

Large diffs are not rendered by default.

File renamed without changes.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@transcom/react-file-viewer",
"version": "1.4.0",
"version": "1.4.1",
"description": "Extendable file viewer for web",
"main": "dist/index.js",
"module": "dist/index.js",
Expand Down
173 changes: 123 additions & 50 deletions src/components/drivers/pdf-viewer.jsx
Original file line number Diff line number Diff line change
@@ -1,72 +1,112 @@
// Copyright (c) 2017 PlanGrid, Inc.

import React from 'react'
import VisibilitySensor from 'react-visibility-sensor'

const INCREASE_PERCENTAGE = 0.2
const DEFAULT_SCALE = 1.1

export class PDFPage extends React.Component {
constructor(props) {
super(props)
this.state = {}
this.onChange = this.onChange.bind(this)
this.canvas = React.createRef()
this.state = {
isVisible: true,
}
this.renderTask = null // Stores the page rendering task for proper canvas handling
}

componentDidMount() {
if (this.props.disableVisibilityCheck) this.fetchAndRenderPage()
if (!this.props.disableVisibilityCheck) {
this.observer = new IntersectionObserver(([entry]) => {
if (entry.target === this.canvas.current) {
this.setState({ isVisible: entry.isIntersecting })
}
})
if (this.canvas.current) this.observer.observe(this.canvas.current)
}
this.fetchAndRenderPage()
}

componentDidUpdate(prevProps, prevState) {
componentDidUpdate(prevProps) {
if (this.props.disableVisibilityCheck) {
if (prevProps.zoom !== this.props.zoom) this.fetchAndRenderPage()
if (
prevProps.zoom !== this.props.zoom ||
prevProps.rotation !== this.props.rotation
) {
this.fetchAndRenderPage()
}
return
}

// we want to render/re-render in two scenarias
// user scrolls to the pdf
// user zooms in
if (
prevState.isVisible === this.state.isVisible &&
prevProps.zoom === this.props.zoom
)
return
if (this.state.isVisible) this.fetchAndRenderPage()
prevProps.zoom !== this.props.zoom ||
prevProps.rotation !== this.props.rotation ||
prevProps.index !== this.props.index ||
prevProps.isVisible !== this.state.isVisible
) {
this.fetchAndRenderPage()
}
}

onChange(isVisible) {
if (isVisible) this.setState({ isVisible })
componentWillUnmount() {
if (this.observer) {
this.observer.disconnect()
}
if (this.renderTask) {
this.renderTask.cancel()
this.renderTask = null
}
}

fetchAndRenderPage() {
const { pdf, index } = this.props
pdf
.getPage(index)
.then(this.renderPage.bind(this))
.catch((error) => {
console.error(`Error fetching page ${index}:`, error)
})
// Make sure current render tasks are cancelled before starting a new one
if (this.renderTask) {
this.renderTask.cancel()
this.renderTask = null
}

if (this.props.disableVisibilityCheck || this.state.isVisible) {
const { pdf, index } = this.props
pdf
.getPage(index)
.then(this.renderPage.bind(this))
.catch((error) => {
console.error(`Error fetching page ${index}:`, error)
})
}
}

renderPage(page) {
try {
const { containerWidth, zoom } = this.props
const { containerWidth, zoom, rotation } = this.props
const initialViewport = page.getViewport({ scale: DEFAULT_SCALE })
const calculatedScale = containerWidth / initialViewport.width
const scale =
(calculatedScale > DEFAULT_SCALE ? DEFAULT_SCALE : calculatedScale) +
zoom * INCREASE_PERCENTAGE
const viewport = page.getViewport({ scale })
const viewport = page.getViewport({ scale, rotation })
const { width, height } = viewport

const context = this.canvas.getContext('2d')
this.canvas.width = width
this.canvas.height = height
const canvas = this.canvas.current
const context = canvas.getContext('2d')
canvas.width = width
canvas.height = height

page.render({
// Store the active render task
this.renderTask = page.render({
canvasContext: context,
viewport,
})

// Handle completion of rendering
this.renderTask.promise
.then(() => {
// Rendering complete, clear the task
this.renderTask = null
})
.catch((error) => {
console.error(`Error rendering page ${this.props.index}:`, error)
})
} catch (error) {
console.error(`Error rendering page ${this.props.index}:`, error)
}
Expand All @@ -76,21 +116,7 @@ export class PDFPage extends React.Component {
const { index } = this.props
return (
<div key={`page-${index}`} className="pdf-canvas">
{this.props.disableVisibilityCheck ? (
<canvas
ref={(node) => (this.canvas = node)}
width="670"
height="870"
/>
) : (
<VisibilitySensor onChange={this.onChange} partialVisibility>
<canvas
ref={(node) => (this.canvas = node)}
width="670"
height="870"
/>
</VisibilitySensor>
)}
<canvas ref={this.canvas} width="670" height="870" />
</div>
)
}
Expand All @@ -104,18 +130,36 @@ export default class PDFDriver extends React.Component {
pdf: null,
zoom: 0,
percent: 0,
rotationValue: 0,
}

this.increaseZoom = this.increaseZoom.bind(this)
this.reduceZoom = this.reduceZoom.bind(this)
this.resetZoom = this.resetZoom.bind(this)
this.rotateLeft = this.rotateLeft.bind(this)
this.rotateRight = this.rotateRight.bind(this)
}

rotateLeft() {
this.setState((prevState) => ({
rotationValue: (prevState.rotationValue - 90 + 360) % 360,
}));
}

rotateRight() {
this.setState((prevState) => ({
rotationValue: (prevState.rotationValue + 90) % 360,
}));
}

componentDidMount() {
// Dynamic import of ESM into CJS
;(async () => {
// sidestep that pdfjs is bundled as esm
const pdfjs = await import('pdfjs-dist/webpack')
const pdfjs = await import(
// Make sure we add comments to this import so the webpack can chunk it properly
/* webpackPrefetch: 0, webpackChunkName: "pdfjs-dist-webpack" */ 'pdfjs-dist/webpack'
)
const { filePath } = this.props
const containerWidth = this.container.offsetWidth
const loadingTask = pdfjs.getDocument(filePath)
Expand All @@ -125,6 +169,11 @@ export default class PDFDriver extends React.Component {

loadingTask.promise
.then((pdf) => {
if (this.pdf) {
// Attempting to mount a new PDF when one already exists
// Destroy the current PDF and reload the new one
this.pdf.destroy()
}
this.setState({ pdf, containerWidth })
})
.catch((error) => {
Expand All @@ -141,10 +190,19 @@ export default class PDFDriver extends React.Component {
}

componentWillUnmount() {
const { pdf } = this.state
if (pdf) {
pdf.destroy()
this.setState({ pdf: null })
if (this.pdf) {
this.pdf.destroy()
this.pdf = null
}
}

componentDidUpdate(prevProps) {
if (this.props.filePath !== prevProps.filePath) {
if (this.pdf) {
this.pdf.destroy()
this.pdf = null
}
this.loadPdf()
}
}

Expand Down Expand Up @@ -173,7 +231,7 @@ export default class PDFDriver extends React.Component {
}

renderPages() {
const { pdf, containerWidth, zoom } = this.state
const { pdf, containerWidth, zoom, rotationValue } = this.state
if (!pdf) return null
const pages = [...Array(pdf.numPages).keys()].map((i) => i + 1)
return pages.map((_, i) => (
Expand All @@ -183,6 +241,7 @@ export default class PDFDriver extends React.Component {
pdf={pdf}
containerWidth={containerWidth}
zoom={zoom * INCREASE_PERCENTAGE}
rotation={rotationValue}
disableVisibilityCheck={this.props.disableVisibilityCheck}
/>
))
Expand All @@ -202,6 +261,8 @@ export default class PDFDriver extends React.Component {
renderControls({
handleZoomIn: this.increaseZoom,
handleZoomOut: this.reduceZoom,
handleRotateLeft: this.rotateLeft,
handleRotateRight: this.rotateRight,
})
) : (
<div className="pdf-controls-container">
Expand All @@ -223,6 +284,18 @@ export default class PDFDriver extends React.Component {
onClick={this.reduceZoom}>
<i className="zoom-out" />
</button>
<button
type="button"
className="view-control"
onClick={this.rotateLeft}>
<i className="rotate-left" />
</button>
<button
type="button"
className="view-control"
onClick={this.rotateRight}>
<i className="rotate-right" />
</button>
</div>
)}

Expand Down
7 changes: 4 additions & 3 deletions webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const path = require('path')
const BUILD_DIR = path.resolve(__dirname, './dist')
const APP_DIR = path.resolve(__dirname, './src')

const BundleAnalyzerPlugin =
require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
.BundleAnalyzerPlugin

const config = {
entry: `${APP_DIR}/components`,
Expand All @@ -18,7 +18,8 @@ const config = {
filename: 'index.js',
library: ['FileViewer'],
libraryTarget: 'umd',
publicPath: '/',
publicPath: '/static/react-file-viewer/',
chunkFilename: '[name].chunk.js',
},
resolve: {
modules: [path.resolve(__dirname, './src'), 'node_modules'],
Expand Down
Loading

0 comments on commit 7c3da43

Please sign in to comment.