Closed spencerdezartsmith closed 4 months ago
I found this issue looking for the same thing.
The docs suggest importing the wrapper using import PWAInstall from '@khmyznikov/pwa-install/dist/pwa-install.react.js'
and there's no type definitions.
I see the react wrapper is declared in src/fallback/react.ts but it doesn't seem to be exported properly in index.ts. I also see the TypeScript source files are surprisingly included in the bundle but when I tried to import them directly using import PWAInstall from '@khmyznikov/pwa-install/src/fallback/react'
the result is of type any
.
@spencerdezartsmith I see you marked this as completed, did you find a solution?
@lnhrdt for react wrapper this types was generated https://github.com/khmyznikov/pwa-install/blob/main/dist/types/fallback/react.d.ts
@khmyznikov I suggest you try using this package on codesandbox with react+typescript template and see why it doesn't work. You either need to adapt package.json and define multiple exports
like https://www.kravchyk.com/typescript-npm-package-json-exports/ or you need to move files in dist
in such a way that react.js
and react.d.ts
are in the same directory so that something like import PWAInstall from '@khmyznikov/pwa-install/dist/react'
works.
@anilanar thanks for hints. I have changed how the react wrapper is built, can you try to use latest commit like this in package.json: "@khmyznikov/pwa-install": "github:khmyznikov/pwa-install"
and check how it works for you?
@lnhrdt @spencerdezartsmith also calling you to help verify the fix.
@khmyznikov The disadvantage of your fix (using exports
) is that it requires the relatively new "Node16"
(or "NodeNext"
) moduleResolution
in tsconfig
. Many projects don't use that new module resolution yet, instead they use "node"
. It's great that you have exports
in package.json, but I think you need to put react.js
and react.d.ts
next to each other for other users.
@anilanar should be doable. But, even "new" node16 security support ended 8 months ago. It's actually old 😅
@khmyznikov You are totally right but... Listen to me for a moment 😄
Most FE projects are single-page apps and use just a bundler like webpack or vite with ES modules. They don't use node.js runtime.
Node.js implemented ESMs with their own "flavor" that contradicted all existing code that used ES modules. All imports must contain file extensions like import foo from './foo.js'
. Typescript, years later, added support for that with a big BUT: you need to import ts files with a js extension. So if you have foo.ts
, it must be imported like import foo from './foo.js'
. With TS 5, they tried to fix that by introducing moduleResolution: bundler
. Now you can import either without extensions or with a ts extension, again a big BUT, you cannot use async imports! It doesn't end there and there are even more problems, but this should be sufficient for convincing 😃
Therefore, most FE codebases still use moduleResolution: node
because there's no reason to use something else, at least for now. In future, if libraries start replacing main
, module
, types
fields with exports
, then yes, everybody will have to play along.
TL;DR node.js fucked up by adding ESMs too late, many years after people adopted ESM. And when they added ESM support, they changed the rules. So nice of them! TS kind of fucked up by adding node+ESM support many years after node added ESM support. They went along with node's rules AND with their insistence on the extension topic: https://github.com/microsoft/TypeScript/issues/49083#issuecomment-1435399267 Libraries and actual users got hurt and lost their respect for ESM.
BTW it seems the following will be fixed with TS 5.5 soonish:
they tried to fix that by introducing
moduleResolution: bundler
... you cannot use async imports!
@anilanar can you check again for moduleResolution: node ? Works ok on my test project.
I think the react types finally fixed
I'll work on this area again this week, I'll give it a try 👍
@anilanar wrapper code shouldn't be needed.
import React, { useEffect, useRef, useState } from 'react';
import PWAInstall from '@khmyznikov/pwa-install/react-legacy';
import { PWAInstallElement } from '@khmyznikov/pwa-install';
function App() {
const appName = 'My PWA';
const [promptEvent, setPromptEvent] = useState(null);
const pwaInstallRef = useRef<PWAInstallElement>(null);
useEffect(() => {
// @ts-ignore
let lastPromptEvent = window.promptEvent;
const intervalId = setInterval(() => {
// @ts-ignore
if (window.promptEvent !== lastPromptEvent) {
// @ts-ignore
lastPromptEvent = window.promptEvent;
// @ts-ignore
setPromptEvent(window.promptEvent); // Update state with new value
}
}, 100); // Check every 100ms
// Cleanup interval on component unmount
return () => {
clearInterval(intervalId);
};
}, []);
return (
<div className="App">
<header className="App-header">
<button onClick={() => pwaInstallRef.current?.install()}>Install</button>
<button onClick={() => pwaInstallRef.current?.hideDialog()}>Hide</button>
<button onClick={() => pwaInstallRef.current?.showDialog(true)}>Show</button>
<PWAInstall ref={pwaInstallRef} externalPromptEvent={promptEvent} name={appName} onPwaInstallAvailableEvent={(event) => console.log(event)}></PWAInstall>
</header>
</div>
);
}
export default App;
Sample with externalPromptEvent in async mode.
@khmyznikov Sadly it doesn't work.
Here's a repro I initialized with tsc --init
and npm init -y
and just changed module
to esnext
and moduleResolution
to node
.
@anilanar not sure how to fix old module resolution. Here's a fully working sample: https://stackblitz.com/edit/vite-react-ts-2eeiak?file=src%2FApp.tsx
Do you have support for typescript that is available for the React Proxy you have provided?
Thanks!