diff --git a/pkg/service/soundtouchweb/static/index.html b/pkg/service/soundtouchweb/static/index.html index a9bf2fc6..e8d8cd07 100644 --- a/pkg/service/soundtouchweb/static/index.html +++ b/pkg/service/soundtouchweb/static/index.html @@ -5,15 +5,6 @@ AfterTouch - diff --git a/pkg/service/soundtouchweb/static/js/app.js b/pkg/service/soundtouchweb/static/js/app.js index eed7ba18..b4f24508 100644 --- a/pkg/service/soundtouchweb/static/js/app.js +++ b/pkg/service/soundtouchweb/static/js/app.js @@ -1,6 +1,6 @@ -import { h, render } from 'preact'; -import { useState, useEffect, useCallback } from 'preact/hooks'; -import htm from 'htm'; +import { h, render } from '/app/static/lib/preact.module.js'; +import { useState, useEffect, useCallback } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { DeviceList } from './components/DeviceList.js'; import { NowPlaying } from './components/NowPlaying.js'; import { Controls } from './components/Controls.js'; diff --git a/pkg/service/soundtouchweb/static/js/components/Announcements.js b/pkg/service/soundtouchweb/static/js/components/Announcements.js index 9790573c..da5a9d3b 100644 --- a/pkg/service/soundtouchweb/static/js/components/Announcements.js +++ b/pkg/service/soundtouchweb/static/js/components/Announcements.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Controls.js b/pkg/service/soundtouchweb/static/js/components/Controls.js index 0b103c00..410e427f 100644 --- a/pkg/service/soundtouchweb/static/js/components/Controls.js +++ b/pkg/service/soundtouchweb/static/js/components/Controls.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/DeviceList.js b/pkg/service/soundtouchweb/static/js/components/DeviceList.js index 4785300f..48838a15 100644 --- a/pkg/service/soundtouchweb/static/js/components/DeviceList.js +++ b/pkg/service/soundtouchweb/static/js/components/DeviceList.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Library.js b/pkg/service/soundtouchweb/static/js/components/Library.js index d8d42229..4af663ed 100644 --- a/pkg/service/soundtouchweb/static/js/components/Library.js +++ b/pkg/service/soundtouchweb/static/js/components/Library.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/NowPlaying.js b/pkg/service/soundtouchweb/static/js/components/NowPlaying.js index 0a243cf4..ab665606 100644 --- a/pkg/service/soundtouchweb/static/js/components/NowPlaying.js +++ b/pkg/service/soundtouchweb/static/js/components/NowPlaying.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect, useRef } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect, useRef } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/PlayURL.js b/pkg/service/soundtouchweb/static/js/components/PlayURL.js index 66e859fa..0c815f73 100644 --- a/pkg/service/soundtouchweb/static/js/components/PlayURL.js +++ b/pkg/service/soundtouchweb/static/js/components/PlayURL.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Presets.js b/pkg/service/soundtouchweb/static/js/components/Presets.js index d17ef62d..455e0ec1 100644 --- a/pkg/service/soundtouchweb/static/js/components/Presets.js +++ b/pkg/service/soundtouchweb/static/js/components/Presets.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/RadioBrowser.js b/pkg/service/soundtouchweb/static/js/components/RadioBrowser.js index ceee67f1..cf43db0f 100644 --- a/pkg/service/soundtouchweb/static/js/components/RadioBrowser.js +++ b/pkg/service/soundtouchweb/static/js/components/RadioBrowser.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Recents.js b/pkg/service/soundtouchweb/static/js/components/Recents.js index 7f2952e9..2bf7be54 100644 --- a/pkg/service/soundtouchweb/static/js/components/Recents.js +++ b/pkg/service/soundtouchweb/static/js/components/Recents.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Sources.js b/pkg/service/soundtouchweb/static/js/components/Sources.js index 864cfe45..e86e78c1 100644 --- a/pkg/service/soundtouchweb/static/js/components/Sources.js +++ b/pkg/service/soundtouchweb/static/js/components/Sources.js @@ -1,5 +1,5 @@ -import { h } from 'preact'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/TTS.js b/pkg/service/soundtouchweb/static/js/components/TTS.js index ae707b24..43a58cf0 100644 --- a/pkg/service/soundtouchweb/static/js/components/TTS.js +++ b/pkg/service/soundtouchweb/static/js/components/TTS.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/TuneInBrowser.js b/pkg/service/soundtouchweb/static/js/components/TuneInBrowser.js index 3b5b44ac..8b8033be 100644 --- a/pkg/service/soundtouchweb/static/js/components/TuneInBrowser.js +++ b/pkg/service/soundtouchweb/static/js/components/TuneInBrowser.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/js/components/Zone.js b/pkg/service/soundtouchweb/static/js/components/Zone.js index c32dedf4..10768e28 100644 --- a/pkg/service/soundtouchweb/static/js/components/Zone.js +++ b/pkg/service/soundtouchweb/static/js/components/Zone.js @@ -1,6 +1,6 @@ -import { h } from 'preact'; -import { useState, useEffect } from 'preact/hooks'; -import htm from 'htm'; +import { h } from '/app/static/lib/preact.module.js'; +import { useState, useEffect } from '/app/static/lib/preact-hooks.module.js'; +import htm from '/app/static/lib/htm.module.js'; import { api } from '../api.js'; const html = htm.bind(h); diff --git a/pkg/service/soundtouchweb/static/lib/preact-hooks.module.js b/pkg/service/soundtouchweb/static/lib/preact-hooks.module.js index db76dd80..8fc6d8e8 100644 --- a/pkg/service/soundtouchweb/static/lib/preact-hooks.module.js +++ b/pkg/service/soundtouchweb/static/lib/preact-hooks.module.js @@ -1,2 +1,2 @@ -import{options as n}from"preact";var t,r,u,i,o=0,f=[],c=n,e=c.__b,a=c.__r,v=c.diffed,l=c.__c,m=c.unmount,p=c.__;function s(n,t){c.__h&&c.__h(r,n,o||t),o=0;var u=r.__H||(r.__H={__:[],__h:[]});return n>=u.__.length&&u.__.push({}),u.__[n]}function d(n){return o=1,y(D,n)}function y(n,u,i){var o=s(t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):D(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}))}],o.__c=r,!r.__f)){var f=function(n,t,r){if(!o.__c.__H)return!0;var u=!1,i=o.__c.props!==n;if(o.__c.__H.__.some(function(n){if(n.__N){u=!0;var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0)}}),c){var f=c.call(this,n,t,r);return u?f||i:f}return!u||i};r.__f=!0;var c=r.shouldComponentUpdate,e=r.componentWillUpdate;r.componentWillUpdate=function(n,t,r){if(this.__e){var u=c;c=void 0,f(n,t,r),c=u}e&&e.call(this,n,t,r)},r.shouldComponentUpdate=f}return o.__N||o.__}function h(n,u){var i=s(t++,3);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__H.__h.push(i))}function _(n,u){var i=s(t++,4);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__h.push(i))}function A(n){return o=5,T(function(){return{current:n}},[])}function F(n,t,r){o=6,_(function(){if("function"==typeof n){var r=n(t());return function(){n(null),r&&"function"==typeof r&&r()}}if(n)return n.current=t(),function(){return n.current=null}},null==r?r:r.concat(n))}function T(n,r){var u=s(t++,7);return C(u.__H,r)&&(u.__=n(),u.__H=r,u.__h=n),u.__}function q(n,t){return o=8,T(function(){return n},t)}function x(n){var u=r.context[n.__c],i=s(t++,9);return i.c=n,u?(null==i.__&&(i.__=!0,u.sub(r)),u.props.value):n.__}function P(n,t){c.useDebugValue&&c.useDebugValue(t?t(n):n)}function b(n){var u=s(t++,10),i=d();return u.__=n,r.componentDidCatch||(r.componentDidCatch=function(n,t){u.__&&u.__(n,t),i[1](n)}),[i[0],function(){i[1](void 0)}]}function g(){var n=s(t++,11);if(!n.__){for(var u=r.__v;null!==u&&!u.__m&&null!==u.__;)u=u.__;var i=u.__m||(u.__m=[0,0]);n.__="P"+i[0]+"-"+i[1]++}return n.__}function j(){for(var n;n=f.shift();){var t=n.__H;if(n.__P&&t)try{t.__h.some(z),t.__h.some(B),t.__h=[]}catch(r){t.__h=[],c.__e(r,n.__v)}}}c.__b=function(n){r=null,e&&e(n)},c.__=function(n,t){n&&t.__k&&t.__k.__m&&(n.__m=t.__k.__m),p&&p(n,t)},c.__r=function(n){a&&a(n),t=0;var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(i.__h.some(z),i.__h.some(B),i.__h=[],t=0)),u=r},c.diffed=function(n){v&&v(n);var t=n.__c;t&&t.__H&&(t.__H.__h.length&&(1!==f.push(t)&&i===c.requestAnimationFrame||((i=c.requestAnimationFrame)||w)(j)),t.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),u=r=null},c.__c=function(n,t){t.some(function(n){try{n.__h.some(z),n.__h=n.__h.filter(function(n){return!n.__||B(n)})}catch(r){t.some(function(n){n.__h&&(n.__h=[])}),t=[],c.__e(r,n.__v)}}),l&&l(n,t)},c.unmount=function(n){m&&m(n);var t,r=n.__c;r&&r.__H&&(r.__H.__.some(function(n){try{z(n)}catch(n){t=n}}),r.__H=void 0,t&&c.__e(t,r.__v))};var k="function"==typeof requestAnimationFrame;function w(n){var t,r=function(){clearTimeout(u),k&&cancelAnimationFrame(t),setTimeout(n)},u=setTimeout(r,35);k&&(t=requestAnimationFrame(r))}function z(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t}function B(n){var t=r;n.__c=n.__(),r=t}function C(n,t){return!n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function D(n,t){return"function"==typeof t?t(n):t}export{q as useCallback,x as useContext,P as useDebugValue,h as useEffect,b as useErrorBoundary,g as useId,F as useImperativeHandle,_ as useLayoutEffect,T as useMemo,y as useReducer,A as useRef,d as useState}; +import{options as n}from"./preact.module.js";var t,r,u,i,o=0,f=[],c=n,e=c.__b,a=c.__r,v=c.diffed,l=c.__c,m=c.unmount,p=c.__;function s(n,t){c.__h&&c.__h(r,n,o||t),o=0;var u=r.__H||(r.__H={__:[],__h:[]});return n>=u.__.length&&u.__.push({}),u.__[n]}function d(n){return o=1,y(D,n)}function y(n,u,i){var o=s(t++,2);if(o.t=n,!o.__c&&(o.__=[i?i(u):D(void 0,u),function(n){var t=o.__N?o.__N[0]:o.__[0],r=o.t(t,n);t!==r&&(o.__N=[r,o.__[1]],o.__c.setState({}))}],o.__c=r,!r.__f)){var f=function(n,t,r){if(!o.__c.__H)return!0;var u=!1,i=o.__c.props!==n;if(o.__c.__H.__.some(function(n){if(n.__N){u=!0;var t=n.__[0];n.__=n.__N,n.__N=void 0,t!==n.__[0]&&(i=!0)}}),c){var f=c.call(this,n,t,r);return u?f||i:f}return!u||i};r.__f=!0;var c=r.shouldComponentUpdate,e=r.componentWillUpdate;r.componentWillUpdate=function(n,t,r){if(this.__e){var u=c;c=void 0,f(n,t,r),c=u}e&&e.call(this,n,t,r)},r.shouldComponentUpdate=f}return o.__N||o.__}function h(n,u){var i=s(t++,3);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__H.__h.push(i))}function _(n,u){var i=s(t++,4);!c.__s&&C(i.__H,u)&&(i.__=n,i.u=u,r.__h.push(i))}function A(n){return o=5,T(function(){return{current:n}},[])}function F(n,t,r){o=6,_(function(){if("function"==typeof n){var r=n(t());return function(){n(null),r&&"function"==typeof r&&r()}}if(n)return n.current=t(),function(){return n.current=null}},null==r?r:r.concat(n))}function T(n,r){var u=s(t++,7);return C(u.__H,r)&&(u.__=n(),u.__H=r,u.__h=n),u.__}function q(n,t){return o=8,T(function(){return n},t)}function x(n){var u=r.context[n.__c],i=s(t++,9);return i.c=n,u?(null==i.__&&(i.__=!0,u.sub(r)),u.props.value):n.__}function P(n,t){c.useDebugValue&&c.useDebugValue(t?t(n):n)}function b(n){var u=s(t++,10),i=d();return u.__=n,r.componentDidCatch||(r.componentDidCatch=function(n,t){u.__&&u.__(n,t),i[1](n)}),[i[0],function(){i[1](void 0)}]}function g(){var n=s(t++,11);if(!n.__){for(var u=r.__v;null!==u&&!u.__m&&null!==u.__;)u=u.__;var i=u.__m||(u.__m=[0,0]);n.__="P"+i[0]+"-"+i[1]++}return n.__}function j(){for(var n;n=f.shift();){var t=n.__H;if(n.__P&&t)try{t.__h.some(z),t.__h.some(B),t.__h=[]}catch(r){t.__h=[],c.__e(r,n.__v)}}}c.__b=function(n){r=null,e&&e(n)},c.__=function(n,t){n&&t.__k&&t.__k.__m&&(n.__m=t.__k.__m),p&&p(n,t)},c.__r=function(n){a&&a(n),t=0;var i=(r=n.__c).__H;i&&(u===r?(i.__h=[],r.__h=[],i.__.some(function(n){n.__N&&(n.__=n.__N),n.u=n.__N=void 0})):(i.__h.some(z),i.__h.some(B),i.__h=[],t=0)),u=r},c.diffed=function(n){v&&v(n);var t=n.__c;t&&t.__H&&(t.__H.__h.length&&(1!==f.push(t)&&i===c.requestAnimationFrame||((i=c.requestAnimationFrame)||w)(j)),t.__H.__.some(function(n){n.u&&(n.__H=n.u,n.u=void 0)})),u=r=null},c.__c=function(n,t){t.some(function(n){try{n.__h.some(z),n.__h=n.__h.filter(function(n){return!n.__||B(n)})}catch(r){t.some(function(n){n.__h&&(n.__h=[])}),t=[],c.__e(r,n.__v)}}),l&&l(n,t)},c.unmount=function(n){m&&m(n);var t,r=n.__c;r&&r.__H&&(r.__H.__.some(function(n){try{z(n)}catch(n){t=n}}),r.__H=void 0,t&&c.__e(t,r.__v))};var k="function"==typeof requestAnimationFrame;function w(n){var t,r=function(){clearTimeout(u),k&&cancelAnimationFrame(t),setTimeout(n)},u=setTimeout(r,35);k&&(t=requestAnimationFrame(r))}function z(n){var t=r,u=n.__c;"function"==typeof u&&(n.__c=void 0,u()),r=t}function B(n){var t=r;n.__c=n.__(),r=t}function C(n,t){return!n||n.length!==t.length||t.some(function(t,r){return t!==n[r]})}function D(n,t){return"function"==typeof t?t(n):t}export{q as useCallback,x as useContext,P as useDebugValue,h as useEffect,b as useErrorBoundary,g as useId,F as useImperativeHandle,_ as useLayoutEffect,T as useMemo,y as useReducer,A as useRef,d as useState}; //# sourceMappingURL=hooks.module.js.map diff --git a/pkg/service/soundtouchweb/static_compatibility_test.go b/pkg/service/soundtouchweb/static_compatibility_test.go new file mode 100644 index 00000000..889b3e71 --- /dev/null +++ b/pkg/service/soundtouchweb/static_compatibility_test.go @@ -0,0 +1,65 @@ +package soundtouchweb + +import ( + "bytes" + "io/fs" + "regexp" + "strings" + "testing" +) + +func TestStaticModulesDoNotRequireImportMaps(t *testing.T) { + index, err := fs.ReadFile(StaticFS, "static/index.html") + if err != nil { + t.Fatalf("read index: %v", err) + } + if bytes.Contains(index, []byte(`type="importmap"`)) { + t.Fatal("index.html must not require import map support") + } + + dependencies := map[string]string{ + "/app/static/lib/preact.module.js": "static/lib/preact.module.js", + "/app/static/lib/preact-hooks.module.js": "static/lib/preact-hooks.module.js", + "/app/static/lib/htm.module.js": "static/lib/htm.module.js", + } + usedDependencies := make(map[string]bool, len(dependencies)) + for publicPath, embeddedPath := range dependencies { + if _, err := fs.Stat(StaticFS, embeddedPath); err != nil { + t.Errorf("static dependency %q: %v", publicPath, err) + } + } + + bareDependency := regexp.MustCompile(`\bfrom\s*['"](?:preact(?:/hooks)?|htm)['"]`) + err = fs.WalkDir(StaticFS, "static", func(path string, entry fs.DirEntry, walkErr error) error { + if walkErr != nil { + return walkErr + } + if entry.IsDir() || !strings.HasSuffix(path, ".js") { + return nil + } + + source, err := fs.ReadFile(StaticFS, path) + if err != nil { + return err + } + if bareDependency.Match(source) { + t.Errorf("%s contains a bare dependency import", path) + } + for publicPath := range dependencies { + if bytes.Contains(source, []byte(publicPath)) { + usedDependencies[publicPath] = true + } + } + + return nil + }) + if err != nil { + t.Fatalf("walk JavaScript modules: %v", err) + } + + for publicPath := range dependencies { + if !usedDependencies[publicPath] { + t.Errorf("static dependency %q is not imported", publicPath) + } + } +} diff --git a/scripts/update-static-deps.sh b/scripts/update-static-deps.sh index 88b641f1..e9818c8b 100755 --- a/scripts/update-static-deps.sh +++ b/scripts/update-static-deps.sh @@ -24,6 +24,13 @@ cp node_modules/preact/dist/preact.module.js "$LIB_DIR/preact.module.js" echo "Copying Preact Hooks..." cp node_modules/preact/hooks/dist/hooks.module.js "$LIB_DIR/preact-hooks.module.js" +# Browsers without import map support need the peer dependency to use a local URL. +sed -i.bak 's/from"preact"/from".\/preact.module.js"/' "$LIB_DIR/preact-hooks.module.js" +rm -f "$LIB_DIR/preact-hooks.module.js.bak" +if ! grep -q 'from".\/preact.module.js"' "$LIB_DIR/preact-hooks.module.js"; then + echo "Failed to rewrite the Preact Hooks peer dependency" >&2 + exit 1 +fi echo "Copying HTM..." cp node_modules/htm/dist/htm.module.js "$LIB_DIR/htm.module.js"