diff --git a/README.md b/README.md index 449ff128..a6c2be4b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) [![sourcegraph: search](https://img.shields.io/badge/sourcegraph-search-brightgreen.svg)](https://sourcegraph.com/github.com/sourcegraph/codeintellify) -Adds code intelligence to code views on the web. Used in [Sourcegraph](https://sourcegraph.com). +This library manages all of the inputs (mouse/keyboard events, location changes, hover information, and hover actions) necessary to display hover tooltips on with a code view. All together, this makes it easier to add code intelligence to code views on the web. Used in [Sourcegraph](https://sourcegraph.com). ## What it does @@ -16,10 +16,12 @@ Adds code intelligence to code views on the web. Used in [Sourcegraph](https://s - When clicking a token, pins the tooltip to that token - Highlights the hovered token +You need to provide your own UI component (referred to as the HoverOverlay) that actually displays this information and exposes these actions to the user. + ## Usage - Call `createHoverifier()` to create a `Hoverifier` object (there should only be one on the page, to have only one HoverOverlay shown). -- The Hoverifier exposes an Observable `hoverStateUpdates` that a consumer can subscribe to, which emits all data needed to render the `HoverOverlay` React component. +- The Hoverifier exposes an Observable `hoverStateUpdates` that a consumer can subscribe to, which emits all data needed to render the HoverOverlay - For each code view on the page, call `hoverifier.hoverify()`, passing the position events coming from `findPositionsFromEvents()`. - `hoverify()` returns a `Subscription` that will "unhoverify" the code view again if unsubscribed from diff --git a/karma.conf.ts b/karma.conf.ts index d3598226..403ca8ac 100644 --- a/karma.conf.ts +++ b/karma.conf.ts @@ -12,12 +12,6 @@ export default (config: Config): void => { included: true, served: true, }, - { - pattern: 'src/**/*.tsx', - watched: false, - included: true, - served: true, - }, ], preprocessors: { 'src/**/*.ts?(x)': ['webpack', 'sourcemap'], @@ -28,7 +22,7 @@ export default (config: Config): void => { // karma-webpack doesn't change the file extensions so we just need to tell karma what these extensions mean. mime: { - 'text/x-typescript': ['ts', 'tsx'], + 'text/x-typescript': ['ts'], }, webpack: webpackConfig, diff --git a/package-lock.json b/package-lock.json index 0bacd771..3f4ecd4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -684,11 +684,6 @@ "integrity": "sha512-kRdHxdAppxYnN7qAQjNTyuG05pjYHFtEUquZauXVXBeaGB4sye3uSkb8wgi34jeaUHG/gWp2f5hQgCCBMizjjA==", "dev": true }, - "@sourcegraph/react-loading-spinner": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/@sourcegraph/react-loading-spinner/-/react-loading-spinner-0.0.7.tgz", - "integrity": "sha512-F4GMp+8XhlRQzEngc+CwbalT8zy8vXMxMrUjhm2cslTjWgWuSft0vSNCmCJDVPshpG/B+Ehb/OzpLLAzsG2JKg==" - }, "@sourcegraph/tsconfig": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sourcegraph/tsconfig/-/tsconfig-3.0.0.tgz", @@ -792,15 +787,15 @@ "dev": true }, "@types/prop-types": { - "version": "15.5.7", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.7.tgz", - "integrity": "sha512-a6WH0fXkgPNiGIuLjjdpf0n/GnmgWZ4vLuVIJJnDwhmRDPEaiRBcy5ofQPh+EJFua0S1QWmk1745+JqZQGnJ8Q==", + "version": "15.5.8", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.8.tgz", + "integrity": "sha512-3AQoUxQcQtLHsK25wtTWIoIpgYjH3vSDroZOUr7PpCHw/jLY1RB9z9E8dBT/OSmwStVgkRNvdh+ZHNiomRieaw==", "dev": true }, "@types/react": { - "version": "16.7.13", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.7.13.tgz", - "integrity": "sha512-WhqrQLAE9z65hfcvWqZfR6qUtIazFRyb8LXqHo8440R53dAQqNkt2OlVJ3FXwqOwAXXg4nfYxt0qgBvE18o5XA==", + "version": "16.7.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.7.18.tgz", + "integrity": "sha512-Tx4uu3ppK53/iHk6VpamMP3f3ahfDLEVt3ZQc8TFm30a1H3v9lMsCntBREswZIW/SKrvJjkb3Hq8UwO6GREBng==", "dev": true, "requires": { "@types/prop-types": "*", @@ -1348,12 +1343,6 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", "dev": true }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", - "dev": true - }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", @@ -2962,15 +2951,6 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, - "encoding": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", - "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", - "dev": true, - "requires": { - "iconv-lite": "~0.4.13" - } - }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -3468,29 +3448,6 @@ "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", "dev": true }, - "fbjs": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", - "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", - "dev": true, - "requires": { - "core-js": "^1.0.0", - "isomorphic-fetch": "^2.1.1", - "loose-envify": "^1.0.0", - "object-assign": "^4.1.0", - "promise": "^7.1.1", - "setimmediate": "^1.0.5", - "ua-parser-js": "^0.7.18" - }, - "dependencies": { - "core-js": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", - "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", - "dev": true - } - } - }, "figures": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", @@ -5181,16 +5138,6 @@ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true }, - "isomorphic-fetch": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", - "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", - "dev": true, - "requires": { - "node-fetch": "^1.0.1", - "whatwg-fetch": ">=0.10.0" - } - }, "issue-parser": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-3.0.0.tgz", @@ -5904,11 +5851,6 @@ "inherits": "^2.0.1" } }, - "mdi-react": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/mdi-react/-/mdi-react-5.1.0.tgz", - "integrity": "sha512-oAZW4/kJVd7iK5pVUsBjiRn4hpc3hUjHt6vgjyXzUAYjvLfYCJkUZqeqOYeFFiEO3ktf/IvSq3+XinojcpkCmg==" - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6303,16 +6245,6 @@ "lodash.toarray": "^4.4.0" } }, - "node-fetch": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", - "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", - "dev": true, - "requires": { - "encoding": "^0.1.11", - "is-stream": "^1.0.1" - } - }, "node-libs-browser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", @@ -9956,15 +9888,6 @@ "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", "dev": true }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dev": true, - "requires": { - "asap": "~2.0.3" - } - }, "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", @@ -10143,15 +10066,15 @@ } }, "react": { - "version": "16.4.2", - "resolved": "https://registry.npmjs.org/react/-/react-16.4.2.tgz", - "integrity": "sha512-dMv7YrbxO4y2aqnvA7f/ik9ibeLSHQJTI6TrYAenPSaQ6OXfb+Oti+oJiy8WBxgRzlKatYqtCjphTgDSCEiWFg==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.7.0.tgz", + "integrity": "sha512-StCz3QY8lxTb5cl2HJxjwLFOXPIFQp+p+hxQfc8WE0QiLfCtIlKj8/+5tjjKm8uSTlAW+fCPaavGFS06V9Ar3A==", "dev": true, "requires": { - "fbjs": "^0.8.16", "loose-envify": "^1.1.0", "object-assign": "^4.1.1", - "prop-types": "^15.6.0" + "prop-types": "^15.6.2", + "scheduler": "^0.12.0" } }, "read-pkg": { @@ -10487,6 +10410,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, + "scheduler": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.12.0.tgz", + "integrity": "sha512-t7MBR28Akcp4Jm+QoR63XgAi9YgCUmgvDHqf5otgAj4QvdoBE4ImCX0ffehefePPG+aitiYHp0g/mW6s4Tp+dw==", + "dev": true, + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, "schema-utils": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", @@ -11518,12 +11451,6 @@ "integrity": "sha512-jw7P2z/h6aPT4AENXDGjcfHTu5CSqzsbZc6YlUIebTyBAq8XaKp78x7VcSh30xwSCcsu5irZkYZUSFP1MrAMbg==", "dev": true }, - "ua-parser-js": { - "version": "0.7.18", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.18.tgz", - "integrity": "sha512-LtzwHlVHwFGTptfNSgezHp7WUlwiqb0gA9AALRbKaERfxwJoiX0A73QbTToxteIAuIaFshhgIZfqK8s7clqgnA==", - "dev": true - }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", @@ -11980,12 +11907,6 @@ "source-map": "~0.6.1" } }, - "whatwg-fetch": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz", - "integrity": "sha512-dcQ1GWpOD/eEQ97k66aiEVpNnapVj90/+R+SXTPYGHpYBBypfKJEQjLrvMZ7YXbKm21gXd4NcuxUTjiv1YtLng==", - "dev": true - }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", diff --git a/package.json b/package.json index 579419ee..6a5c0bd8 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,7 @@ "dependencies": { "@sourcegraph/event-positions": "^1.0.0", "@sourcegraph/extension-api-types": "^1.0.1", - "@sourcegraph/react-loading-spinner": "0.0.7", "lodash": "^4.17.10", - "mdi-react": "^5.1.0", "rxjs": "^6.3.3", "ts-key-enum": "^2.0.0" }, diff --git a/src/HoverOverlay.scss b/src/HoverOverlay.scss deleted file mode 100644 index 652b6b84..00000000 --- a/src/HoverOverlay.scss +++ /dev/null @@ -1,113 +0,0 @@ -@import '../node_modules/@sourcegraph/react-loading-spinner/lib/LoadingSpinner.css'; - -.hover-overlay { - position: absolute; - min-width: 6rem; - max-width: 32rem; - max-height: 15rem; - display: flex; - flex-direction: column; - align-items: stretch; - z-index: 100; - - $animation-duration: 100ms; - transition: opacity $animation-duration ease-in-out; - - &__close-button { - position: absolute; - top: 0; - right: 0; - padding: 0.25rem; - border-radius: 0; - background: transparent; - z-index: 1; - border: none; - opacity: 0; - transition: opacity $animation-duration ease-in-out; - &:focus { - outline: none; // override GitHub style - } - &:active { - box-shadow: none; // override GitHub style - } - } - &:hover &__close-button { - opacity: 1; - } - - &__row { - display: block; - width: 100%; - margin: 0; - &:not(:first-child) { - border-top: 1px solid var(--border-color); - } - hr { - margin: 0.5rem -0.5rem; - background: var(--border-color); - } - p, - pre { - &:not(:last-child) { - margin-bottom: 0.5rem; - } - &:last-child { - margin-bottom: 0; - } - } - } - - &__contents { - flex: 1 1 auto; - overflow-y: auto; - } - - &__content { - padding: 0.5rem; - overflow-x: auto; - word-wrap: normal; - p:last-child { - margin-bottom: 0; - } - } - - &__actions { - flex: 0 0 auto; - display: flex; - } - - &__action:not(:first-child) { - border-left: 1px solid var(--border-color); - } - - &__action { - text-align: center; - border: none; - } - - &__action, - &__actions-placeholder { - flex: 1 1 auto; - border-radius: 0; - } - - &__loader-row { - text-align: center; - } - - &__loader-row, - &__hover-error, - &__content-error, - &__alert-below { - padding: 0.5rem; - } - - &__alert-below { - margin: 0; - overflow-y: auto; - } - - code { - white-space: pre; - } -} diff --git a/src/HoverOverlay.tsx b/src/HoverOverlay.tsx deleted file mode 100644 index 4c49de8e..00000000 --- a/src/HoverOverlay.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import { LoadingSpinner } from '@sourcegraph/react-loading-spinner' -import { upperFirst } from 'lodash' -import AlertCircleOutlineIcon from 'mdi-react/AlertCircleOutlineIcon' -import CloseIcon from 'mdi-react/CloseIcon' -import InformationOutlineIcon from 'mdi-react/InformationOutlineIcon' -import * as React from 'react' -import { ErrorLike, isErrorLike } from './errors' -import { toNativeEvent } from './helpers' -import { HoveredToken } from './token_position' -import { HoverAttachment, LOADING } from './types' - -/** - * The component used to render an action. - * - * @template A The type of an action. - */ -export type ActionComponent = React.ComponentType> - -/** - * @template C Extra context for the hovered token. - * @template D The type of the hover content data. - * @template A The type of an action. - */ -export interface HoverOverlayProps { - /** What to show as contents */ - hoverOrError?: typeof LOADING | (HoverAttachment & D) | null | ErrorLike // TODO disallow null and undefined - - /** The position of the tooltip (assigned to `style`) */ - overlayPosition?: { left: number; top: number } - - /** A ref callback to get the root overlay element. Use this to calculate the position. */ - hoverRef?: React.Ref - - /** - * The hovered token (position and word). - * Used for the Find References buttons and for error messages - */ - hoveredToken?: HoveredToken & C - - /** Whether to show the close button for the hover overlay */ - showCloseButton: boolean - - /** - * Actions to display as buttons or links in the hover. - */ - actionsOrError?: typeof LOADING | A[] | null | ErrorLike - - /** An optional class name to apply to the outermost element of the HoverOverlay */ - className?: string - - /** Called when the close button is clicked */ - onCloseButtonClick?: (event: MouseEvent) => void -} - -const transformMouseEvent = (handler: (event: MouseEvent) => void) => (event: React.MouseEvent) => - handler(toNativeEvent(event)) - -/** - * @template C Extra context for the hovered token. - * @template D The type of the hover content data. - * @template A The type of an action. - */ -export const HoverOverlay: ( - props: HoverOverlayProps & { - /** The content of the hover overlay. */ - children?: React.ReactNode | React.ReactNode[] - - /** The component used to render actions. */ - actionComponent: ActionComponent - } -) => React.ReactElement = ({ - hoverOrError, - hoverRef, - children, - onCloseButtonClick, - overlayPosition, - showCloseButton, - actionsOrError, - actionComponent: ActionComponent, - className = '', -}) => ( -
- {showCloseButton && ( - - )} -
- {hoverOrError === LOADING ? ( -
- -
- ) : isErrorLike(hoverOrError) ? ( -
-

- Error fetching hover from language server: -

- {upperFirst(hoverOrError.message)} -
- ) : ( - children - )} -
- {actionsOrError === null ? ( -
- No definition found -
- ) : isErrorLike(actionsOrError) ? ( -
- - Error finding definition: - {' '} - {upperFirst(actionsOrError.message)} -
- ) : ( - actionsOrError !== undefined && - actionsOrError !== LOADING && ( -
- {actionsOrError.map((action, i) => ( - - ))} -
- ) - )} -
-) diff --git a/src/hoverifier.test.ts b/src/hoverifier.test.ts index 0bb1f848..7ae6349c 100644 --- a/src/hoverifier.test.ts +++ b/src/hoverifier.test.ts @@ -4,6 +4,7 @@ import { EMPTY, NEVER, Observable, of, Subject, Subscription } from 'rxjs' import { distinctUntilChanged, filter, map } from 'rxjs/operators' import { TestScheduler } from 'rxjs/testing' +import { ErrorLike } from './errors' import { propertyIsDefined } from './helpers' import { AdjustmentDirection, @@ -14,12 +15,11 @@ import { PositionJump, TOOLTIP_DISPLAY_DELAY, } from './hoverifier' -import { HoverOverlayProps } from './HoverOverlay' import { findPositionsFromEvents, SupportedMouseEvent } from './positions' import { CodeViewProps, DOM } from './testutils/dom' import { createHoverAttachment, createStubActionsFetcher, createStubHoverFetcher } from './testutils/fixtures' import { dispatchMouseEventAtPositionImpure } from './testutils/mouse' -import { LOADING } from './types' +import { HoverAttachment, LOADING } from './types' describe('Hoverifier', () => { const dom = new DOM() @@ -382,7 +382,10 @@ describe('Hoverifier', () => { 1}ms b` const outputValues: { - [key: string]: Pick, 'hoverOrError' | 'actionsOrError'> + [key: string]: { + hoverOrError: typeof LOADING | (HoverAttachment) | null | ErrorLike + actionsOrError: typeof LOADING | string[] | null | ErrorLike + } } = { // No hover is shown if it would just consist of LOADING. a: { hoverOrError: createHoverAttachment(hover), actionsOrError: LOADING }, diff --git a/src/hoverifier.ts b/src/hoverifier.ts index b8cb2e2e..6314c6f0 100644 --- a/src/hoverifier.ts +++ b/src/hoverifier.ts @@ -30,7 +30,6 @@ import { import { Key } from 'ts-key-enum' import { asError, ErrorLike, isErrorLike } from './errors' import { scrollIntoCenterIfNeeded } from './helpers' -import { HoverOverlayProps } from './HoverOverlay' import { calculateOverlayPosition } from './overlay_position' import { DiffPart, PositionEvent, SupportedMouseEvent } from './positions' import { createObservableStateContainer } from './state' @@ -42,7 +41,7 @@ import { getTokenAtPosition, HoveredToken, } from './token_position' -import { HoverAttachment, isPosition, LineOrPositionOrRange, LOADING } from './types' +import { HoverAttachment, HoverOverlayProps, isPosition, LineOrPositionOrRange, LOADING } from './types' export { HoveredToken } diff --git a/src/index.ts b/src/index.ts index e93e5ed5..ac494abd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,2 @@ export * from './hoverifier' -export * from './HoverOverlay' export * from './positions' diff --git a/src/types.ts b/src/types.ts index 4cd57e7c..73d87c52 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,7 +1,36 @@ import { Position, Range } from '@sourcegraph/extension-api-types' +import { ErrorLike } from './errors' +import { HoveredToken } from './token_position' export const LOADING: 'loading' = 'loading' +/** + * @template C Extra context for the hovered token. + * @template D The type of the hover content data. + * @template A The type of an action. + */ +export interface HoverOverlayProps { + /** What to show as contents */ + hoverOrError?: typeof LOADING | (HoverAttachment & D) | null | ErrorLike // TODO disallow null and undefined + + /** The position of the tooltip (assigned to `style`) */ + overlayPosition?: { left: number; top: number } + + /** + * The hovered token (position and word). + * Used for the Find References buttons and for error messages + */ + hoveredToken?: HoveredToken & C + + /** Whether to show the close button for the hover overlay */ + showCloseButton: boolean + + /** + * Actions to display as buttons or links in the hover. + */ + actionsOrError?: typeof LOADING | A[] | null | ErrorLike +} + /** * Describes the range in the document (usually a token) that the hover is attached to. */ diff --git a/tsconfig.json b/tsconfig.json index 64fadd42..762d8e72 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,7 +9,6 @@ "outDir": "lib", "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "jsx": "react", "lib": ["es2017", "dom", "dom.iterable"] } } diff --git a/webpack.test.config.ts b/webpack.test.config.ts index 7b72aabb..fed4d2b7 100644 --- a/webpack.test.config.ts +++ b/webpack.test.config.ts @@ -12,13 +12,13 @@ const config: Configuration = { exclude: /node_modules/, }, { - test: /\.tsx?$/, + test: /\.ts$/, use: 'awesome-typescript-loader', exclude: /node_modules/, }, { - test: /src\/.*\.tsx?$/, - exclude: /(node_modules|\.test\.tsx?$|\.d.ts$)/, + test: /src\/.*\.ts$/, + exclude: /(node_modules|\.test\.ts$|\.d.ts$)/, loader: 'istanbul-instrumenter-loader', include: path.resolve(__dirname, 'src'), enforce: 'post', @@ -29,7 +29,7 @@ const config: Configuration = { ], }, resolve: { - extensions: ['.tsx', '.ts', '.js', '.html'], + extensions: ['.ts', '.js', '.html'], }, output: { filename: '[name].js',