Fordi / app-skeleton

Template for a zero-build webapp based on preact + htm
11 stars 2 forks source link

PWA usage #1

Open badpenguin opened 1 year ago

badpenguin commented 1 year ago

I wish to use preact, hook, htm and signal in a PWA so i need to store the files locally.

Do you have any suggestions how to do this?

Fordi commented 1 year ago

I'm not sure what you're asking for. Nothing about a progressive webapp necessitates you not get resources from a CDN.

Still, you can use rollup to pull down all the necessary stuff for a given item under tools if needs be:

# Install rollup and the necessary plugins
npm i -D rollup @rollup/plugin-node-resolve @rollup/plugin-commonjs
# Install the deps
npm i -D htm preact

For each dep, create a file that looks somthing like this (the exact code may vary depending on how the module was originally compiled, similar to how the importmap URL for a dep can vary):

tmp/htm.js

import * as d from "htm";
export default d;

tmp/preact.js

import * as d from "preact";
export default d;

tmp/preactHooks.js

import * as d from "preact";
export default d;

Create a config file for rollup:

configs/rollup.config.mjs

// Generic config file for rolling up dev deps into a lib file
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';

export default {
  plugins: [nodeResolve({
    exportConditions: ['node'],
    browser: true,
  }), commonjs()]
};
# Roll each tmp/{dep}.js into vendor/{dep}.js
while read depFile; do
  npx rollup --format=es --input "$depFile" -c configs/rollup.config.mjs -o "src/vendor/$(basename "$depFile")"
done< <(find tmp -iname '*.js')

Update the importmap appropriately. You can remove the React stuff if you're not going to use it.

src/index.html

    <script type="importmap">
      {
        "imports": {
          "preact": "./vendor/preact.js",
          "preact/hooks": "vendor/preactHooks.js",
          "htm": "./vendor/htm.js",
          "reactor/preact": "./tools/reactor-preact.js",
          "reactor": "./tools/reactor.js",
          "html": "./tools/html.js",
          "css": "./tools/css.js",
          "classes": "./tools/classes.js",
          "asyncComponent": "./tools/asyncComponent.js",
          "asyncComponents": "./tools/asyncComponents.js",
          "createI18nContext": "./tools/createI18nContext.js",
          "apiClient": "./tools/apiClient.js",
          "endpoint": "./tools/endpoint.js",
          "importFont": "./tools/importFont.js",
          "makeResolver": "./tools/makeResolver.js",
          "useResource": "./tools/useResource.js",
          "useScheduled": "./tools/useScheduled.js",
          "useParamState": "./tools/useParamState.js",
          "useUid": "./tools/useUid.js",
          "StateMachine": "./tools/StateMachine.js",
          "PathRouter": "./tools/PathRouter.js"
        }
      }
    </script>

Gimme a minute, and I'll write a script to eject specific deps.

badpenguin commented 1 year ago

Do you think is it ok to just do "npm install $module" and then pick files from the dist named $module.module.js ? Also i've seen "htm" has a standalone preact build that includes hooks too but when using signals it seems missing the "options" export :-(

Fordi commented 1 year ago

Nah, that won't work; stuff outside of ./src wouldn't be available to the browser.

I've just pushed a commit for a command, npm run eject. Just list the deps you want as vendor scripts after that command; it should work.

e.g.: npm run eject htm preact@^10 preact/hooks@^10 signal will create the files you need in src/vendor and update src/index.html to point at 'em.

* the "@^10" isn't necessary; it's just to show that eject supports picking versions.

badpenguin commented 1 year ago

Nah, that won't work; stuff outside of ./src wouldn't be available to the browser.

I've just pushed a commit for a command, npm run eject. Just list the deps you want as vendor scripts after that command; it should work.

e.g.: npm run eject htm preact@^10 preact/hooks@^10 signal will create the files you need in src/vendor and update src/index.html to point at 'em.

  • the "@^10" isn't necessary; it's just to show that eject supports picking versions.

Thank you I tried it, the result is slighty larger than the *.module.js version into the npm's "dist" dirs.

However it seems "h" not being exported Uncaught SyntaxError: The requested module 'preact' does not provide an export named 'h' (at page-home.js:1:10) and main-app.js:2 Uncaught SyntaxError: The requested module '@preact/signals' does not provide an export named 'computed' (at main-app.js:2:18)

To be clear, i'm using them as esm modules:

    <script type="importmap">
      {
        "imports": {
          "preact": "./app/dist2/preact.js",
          "preact/hooks": "./app/dist2/preact--hooks.js",
          "htm": "./app/dist2/htm.js",
          "@preact/signals": "./app/dist2/_preact--signals.js",
          "preact-router": "./app/dist2/preact-router.js"
        }
      }
    </script>

    <script type="module">
        import {h, render} from 'preact';
        import {MainApp} from './app/main-app.js';
        const app = h(MainApp);
        render(app, document.getElementById("main"));
    </script>
Fordi commented 1 year ago

You should be able to see the exports by opening up the vendor files; you get the minified code up top, but Rollup is kind enough to show the structure below it.

Fordi commented 1 year ago

Also, what's dist2?

badpenguin commented 1 year ago

You should be able to see the exports by opening up the vendor files; you get the minified code up top, but Rollup is kind enough to show the structure below it.

dist2, dist3 are the dirs where i am copying the builded files from src/vendor/

This is the complete example:

    <script type="importmap">
      {
        "imports": {
          "preact": "./app/dist3/preact.js",
          "preact/hooks": "./app/dist3/preact--hooks.js",
          "htm": "./app/dist3/htm.js",
          "@preact/signals": "./app/dist3/_preact-signals.js",
          "preact-router": "./app/dist3/preact-router.js"
        }
      }
    </script>

    <script type="module">
        import {h, render} from 'preact';
        //import {MainApp} from './app/main-app.js';
        const MainApp = () => 'MAINAPP';
        const app = h(MainApp);
        render(app, document.getElementById("main"));
    </script>

It still says: Uncaught SyntaxError: The requested module 'preact' does not provide an export named 'h' (at (index):114:11)

I tried to modify the first example you proposed by compiling preact with this code:

import * as d from "preact";
export const { Component, Fragment, cloneElement, createContext, createElement, createRef, h, render,toChildArray, options, isValidElement,hydrate  } = d;

this solve the export problem but generates new unknown errors.