diff --git a/config/webpack.library.js b/config/webpack.library.js index 4c3ff7b3..24c47e25 100644 --- a/config/webpack.library.js +++ b/config/webpack.library.js @@ -55,7 +55,7 @@ module.exports = { maxAssetSize: 9000000 }, entry: { - "bundle.min": "./js/webamp.js", + "bundle.min": "./js/webamp.ts", "lazy-bundle.min": "./js/webampLazy.tsx" }, output: { diff --git a/demo/config/webpack.common.js b/demo/config/webpack.common.js index edada5a1..b56df75b 100644 --- a/demo/config/webpack.common.js +++ b/demo/config/webpack.common.js @@ -93,7 +93,7 @@ module.exports = { maxAssetSize: 7000000 }, entry: { - webamp: ["./js/index.js"] + webamp: ["./js/index.tsx"] }, context: path.resolve(__dirname, "../"), output: { diff --git a/demo/js/index.js b/demo/js/index.tsx similarity index 91% rename from demo/js/index.js rename to demo/js/index.tsx index 0680d16d..eb6ad7e5 100644 --- a/demo/js/index.js +++ b/demo/js/index.tsx @@ -5,6 +5,8 @@ import React from "react"; import ReactDOM from "react-dom"; import createMiddleware from "raven-for-redux"; import isButterchurnSupported from "butterchurn/lib/isSupported.min"; +import JSZip from "jszip"; +// @ts-ignore import base from "../../skins/base-2.91-png.wsz"; import { WINDOWS } from "../../js/constants"; import * as Selectors from "../../js/selectors"; @@ -40,6 +42,9 @@ import WebampIcon from "./WebampIcon"; import enableMediaSession from "./mediaSession"; import screenshotInitialState from "./screenshotInitialState"; +declare const SENTRY_DSN: string | undefined; +declare const COMMITHASH: string | undefined; + const DEFAULT_DOCUMENT_TITLE = document.title; const NOISY_ACTION_TYPES = new Set([ @@ -53,7 +58,7 @@ const NOISY_ACTION_TYPES = new Set([ const MIN_MILKDROP_WIDTH = 725; -let screenshot = false; +let screenshot = null; let clearState = false; let useState = false; let skinUrl = configSkinUrl; @@ -112,9 +117,13 @@ window.addEventListener("beforeinstallprompt", e => { }); Raven.context(async () => { + // @ts-ignore window.Raven = Raven; if (screenshot) { - document.getElementsByClassName("about")[0].style.visibility = "hidden"; + const aboutNode = document.getElementsByClassName("about")[0]; + if (aboutNode != null) { + (aboutNode as HTMLElement).style.visibility = "hidden"; + } } if (!WebampLazy.browserIsSupported()) { document.getElementById("browser-compatibility").style.display = "block"; @@ -172,8 +181,8 @@ Raven.context(async () => { availableSkins, filePickers: [dropboxFilePicker], enableHotkeys: true, - requireJSZip: () => - import(/* webpackChunkName: "jszip" */ "jszip/dist/jszip"), + requireJSZip: async () => + (await import(/* webpackChunkName: "jszip" */ "jszip")).default, requireMusicMetadata: () => import(/* webpackChunkName: "music-metadata-browser" */ "music-metadata-browser/dist/index"), __enableMediaLibrary: library, @@ -231,12 +240,15 @@ Raven.context(async () => { fileInput.style.display = "none"; fileInput.type = "file"; fileInput.value = null; - fileInput.addEventListener("change", e => { - webamp.store.dispatch(loadFilesFromReferences(e.target.files)); + fileInput.addEventListener("change", (e: Event) => { + webamp.store.dispatch( + loadFilesFromReferences((e.target as HTMLInputElement).files) + ); }); document.body.appendChild(fileInput); // Expose webamp instance for debugging and integration tests. + // @ts-ignore window.__webamp = webamp; await bindToIndexedDB(webamp, clearState, useState); diff --git a/js/actionCreators/files.ts b/js/actionCreators/files.ts index 1e7d9502..99e60bb6 100644 --- a/js/actionCreators/files.ts +++ b/js/actionCreators/files.ts @@ -1,5 +1,6 @@ import { parser, creator } from "winamp-eqf"; import { BANDS, LOAD_STYLE } from "../constants"; +import JSZip from "jszip"; import * as Utils from "../utils"; @@ -88,7 +89,7 @@ export function setSkinFromArrayBuffer( return; } dispatch({ type: LOADING }); - let JSZip; + let JSZip: JSZip; try { JSZip = await requireJSZip(); } catch (e) { diff --git a/js/types.ts b/js/types.ts index a5c948a1..b53deaf2 100644 --- a/js/types.ts +++ b/js/types.ts @@ -1,3 +1,4 @@ +import JSZip from "jszip"; import { PlaylistState } from "./reducers/playlist"; import { SettingsState } from "./reducers/settings"; import { UserInputState } from "./reducers/userInput"; @@ -308,7 +309,7 @@ export type Action = } | { type: "SET_DUMMY_VIZ_DATA"; - data: null; + data: DummyVizData; } | { type: "SET_BAND_VALUE"; @@ -641,7 +642,7 @@ export interface IMusicMetadataBrowserApi { } export interface Extras { - requireJSZip(): Promise; + requireJSZip(): Promise; requireMusicMetadata(): Promise; convertPreset: ((file: File) => Promise) | null; handleTrackDropEvent?: ( diff --git a/js/webamp.js b/js/webamp.js deleted file mode 100644 index c1027ec9..00000000 --- a/js/webamp.js +++ /dev/null @@ -1,15 +0,0 @@ -import JSZip from "jszip"; -import * as musicMetadataBrowser from "music-metadata-browser"; -import WebampLazy from "./webampLazy"; - -class Winamp extends WebampLazy { - constructor(options) { - super({ - ...options, - requireJSZip: () => JSZip, - requireMusicMetadata: () => musicMetadataBrowser - }); - } -} - -export default Winamp; diff --git a/js/webamp.ts b/js/webamp.ts new file mode 100644 index 00000000..ecae7a36 --- /dev/null +++ b/js/webamp.ts @@ -0,0 +1,15 @@ +import JSZip from "jszip"; +import * as musicMetadataBrowser from "music-metadata-browser"; +import WebampLazy, { Options } from "./webampLazy"; + +class Winamp extends WebampLazy { + constructor(options: Options) { + super({ + ...options, + requireJSZip: () => Promise.resolve(JSZip), + requireMusicMetadata: () => Promise.resolve(musicMetadataBrowser) + }); + } +} + +export default Winamp; diff --git a/js/webampLazy.tsx b/js/webampLazy.tsx index a94209b9..7e702db4 100644 --- a/js/webampLazy.tsx +++ b/js/webampLazy.tsx @@ -1,6 +1,7 @@ import React from "react"; import ReactDOM from "react-dom"; import { Provider } from "react-redux"; +import JSZip from "jszip"; import { Store, @@ -39,8 +40,9 @@ import Emitter from "./emitter"; import "../css/base-skin.css"; import { SerializedStateV1 } from "./serializedStates/v1Types"; import Disposable from "./Disposable"; +import { DeepPartial } from "redux"; -interface Options { +export interface Options { /** * An object representing the initial skin to use. * @@ -104,26 +106,26 @@ interface Options { requiresNetwork: boolean; } ]; - zIndex: number; + zIndex?: number; } interface PrivateOptions { avaliableSkins?: { url: string; name: string }[]; // Old misspelled name - requireJSZip(): Promise; // TODO: Type JSZip + requireJSZip(): Promise; // TODO: Type JSZip requireMusicMetadata(): Promise; // TODO: Type musicmetadata handleTrackDropEvent?: ( e: React.DragEvent ) => Track[] | null | Promise; - __initialState?: AppState; + __initialState?: DeepPartial; __customMiddlewares?: Middleware[]; __enableMediaLibrary?: boolean; - __initialWindowLayout: { + __initialWindowLayout?: { [windowId: string]: { size: null | [number, number]; position: WindowPosition; }; }; - __butterchurnOptions: ButterchurnOptions; + __butterchurnOptions?: ButterchurnOptions; } // Return a promise that resolves when the store matches a predicate. diff --git a/package.json b/package.json index 5f2614fe..3ddb21a2 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@babel/runtime": "^7.0.0", "@types/classnames": "^2.2.6", "@types/fscreen": "^1.0.1", + "@types/jszip": "^3.1.5", "@types/invariant": "^2.2.29", "@types/jest": "^23.3.2", "@types/lodash": "^4.14.116", diff --git a/yarn.lock b/yarn.lock index 65b56dc9..2f896e66 100644 --- a/yarn.lock +++ b/yarn.lock @@ -726,6 +726,12 @@ version "23.3.2" resolved "https://registry.yarnpkg.com/@types/jest/-/jest-23.3.2.tgz#07b90f6adf75d42c34230c026a2529e56c249dbb" +"@types/jszip@^3.1.5": + version "3.1.5" + resolved "https://registry.yarnpkg.com/@types/jszip/-/jszip-3.1.5.tgz#664b424b15aadf0489e871d319f4b18ddc6e24ea" + dependencies: + "@types/node" "*" + "@types/lodash-es@^4.17.1": version "4.17.1" resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.1.tgz#56745e5411558362aeca31def918f88f725dd29d"