diff --git a/.github/workflows/deno.yaml b/.github/workflows/deno.yaml index 62b1d66..85c3c26 100644 --- a/.github/workflows/deno.yaml +++ b/.github/workflows/deno.yaml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - deno-version: [1.x] + deno-version: [2.x] timezone: ["Europe/Stockholm"] steps: diff --git a/.gitignore b/.gitignore index 5ae071b..7dba47b 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ pup.jsonc.ipc # Fresh build directory _fresh/ + +# Node modules (npm packages) +node_modules/ diff --git a/FRESH_2_MIGRATION.md b/FRESH_2_MIGRATION.md new file mode 100644 index 0000000..620f4cd --- /dev/null +++ b/FRESH_2_MIGRATION.md @@ -0,0 +1,146 @@ +# Fresh 2.1 Migration Guide + +This document describes the migration from Fresh 1.6.8 to Fresh 2.1.3 and the move from deno.land/x to JSR packages. + +## Changes Made + +### 1. Fresh Framework Update + +- **Before:** `https://deno.land/x/fresh@1.6.8/` +- **After:** `jsr:@fresh/core@^2.1.3` + +Fresh 2.x has moved from deno.land/x to JSR (JavaScript Registry). The new package is `@fresh/core` on JSR. + +### 2. Import Path Changes + +All imports from `$fresh/*` have been updated to `fresh/*`: + +- `$fresh/server.ts` → `fresh/server` +- `$fresh/dev.ts` → `fresh/dev` +- `$fresh/runtime.ts` → `fresh/runtime` + +**Files Updated:** +- main.ts +- dev.ts +- fresh.gen.ts +- All route files (*.tsx, *.ts in routes/) +- All island files (*.tsx in islands/) +- All component files that import Fresh types + +### 3. Preact and Signals Migration + +Moved from esm.sh to npm packages (Fresh 2.x requirement): + +- `@preact/signals`: `https://esm.sh/*@preact/signals@1.2.2` → `npm:@preact/signals@^2.3.2` +- `@preact/signals-core`: `https://esm.sh/*@preact/signals-core@1.5.1` → `npm:@preact/signals-core@^1.8.0` +- `preact`: `https://esm.sh/preact@10.19.6` → `npm:preact@^10.27.2` +- `preact-render-to-string`: `https://esm.sh/*preact-render-to-string@6.2.2` → `npm:preact-render-to-string@^6.5.15` + +### 4. Compiler Options Update + +Updated for Fresh 2.x JSX precompilation: + +```json +{ + "compilerOptions": { + "lib": ["dom", "dom.asynciterable", "dom.iterable", "deno.ns"], + "jsx": "precompile", + "jsxImportSource": "preact", + "jsxPrecompileSkipElements": [ + "a", "img", "source", "body", "html", "head", + "title", "meta", "script", "link", "style", + "base", "noscript", "template" + ] + } +} +``` + +### 5. Node Modules Directory + +Added `"nodeModulesDir": "auto"` to deno.json for better npm package handling. + +### 6. Fresh Update Task + +Updated the Fresh update command: + +- **Before:** `deno run -A -r https://fresh.deno.dev/update .` +- **After:** `deno run -A -r jsr:@fresh/update .` + +## Packages Still on deno.land/x + +The following packages remain on deno.land/x and should be evaluated for JSR migration when possible: + +1. **entsoe_api_client** (`@1.0.3`) + - Specific ENTSO-E API client + - Likely to remain on deno.land/x (niche package) + +2. **fresh_seo** (`@1.0.1`) + - Fresh SEO plugin + - May need compatibility update for Fresh 2.x + - Check for Fresh 2.x compatible version or JSR alternative + +3. **glob_filter** (`@1.0.1`) + - Small utility package + - Likely to remain on deno.land/x + +4. **localekit_fresh** (`@0.5.2`) + - i18n plugin for Fresh + - May need compatibility update for Fresh 2.x + - Check for Fresh 2.x compatible version or JSR alternative + +5. **sqlite3** (`@0.11.1`) + - SQLite FFI binding + - Potentially available on JSR as `@db/sqlite` + - Should be evaluated when JSR access is available + +6. **xml** (`@2.1.3`) + - XML parsing library + - May have JSR alternatives + - Should be evaluated when JSR access is available + +## Testing Checklist + +Once JSR access is enabled in the build environment, test the following: + +- [ ] Fresh 2.x dependencies download successfully +- [ ] Application starts without errors (`deno task dev`) +- [ ] All routes render correctly +- [ ] All islands work with client-side interactivity +- [ ] Middleware functions correctly +- [ ] API routes respond properly +- [ ] SEO plugin (fresh_seo) works with Fresh 2.x +- [ ] i18n plugin (localekit_fresh) works with Fresh 2.x +- [ ] Database operations work correctly +- [ ] Static file serving works +- [ ] Tests pass (`deno test`) +- [ ] Build process works (`deno task build`) +- [ ] Production mode works (`deno task prod`) + +## Breaking Changes to Watch For + +Fresh 2.x introduced some breaking changes: + +1. **Import paths**: All `$fresh/*` imports must be updated (✅ Done) +2. **JSX precompilation**: Required for Fresh 2.x (✅ Configured) +3. **npm packages**: Preact and signals must come from npm (✅ Done) +4. **Plugin API**: Some plugins may need updates for Fresh 2.x compatibility + +## Plugin Compatibility + +The following Fresh plugins need compatibility verification: + +- **fresh_seo**: Check if compatible with Fresh 2.x or needs update +- **localekit_fresh**: Check if compatible with Fresh 2.x or needs update + +## Future Migrations + +Consider migrating these packages to JSR when available: + +- sqlite3 → Check for @db/sqlite on JSR +- xml → Check for @std/xml or alternatives on JSR + +## References + +- [Fresh 2.0 Announcement](https://deno.com/blog/fresh-2) +- [Fresh Documentation](https://fresh.deno.dev/) +- [JSR - JavaScript Registry](https://jsr.io/) diff --git a/components/layout/SwHead.tsx b/components/layout/SwHead.tsx index 98edea5..98df062 100644 --- a/components/layout/SwHead.tsx +++ b/components/layout/SwHead.tsx @@ -1,10 +1,10 @@ -import { asset, Head } from "$fresh/runtime.ts"; +import { asset, Head } from "fresh/runtime"; import { Country, DataArea } from "config/countries.ts"; import { maxPrice, minPrice, processPrice } from "utils/price.ts"; import { avgPrice } from "utils/price.ts"; import { applyExchangeRate } from "utils/price.ts"; import { locale_kit } from "localekit_fresh"; -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { preferences } from "config/preferences.js"; interface HeadProps extends PageProps { diff --git a/deno.json b/deno.json index c255564..1de4972 100644 --- a/deno.json +++ b/deno.json @@ -1,4 +1,5 @@ { + "nodeModulesDir": "auto", "tasks": { "build": "deno bundle backend/scheduler/jobs/daily.currencyupdate.ts dist/daily.currencyupdate.ts && deno bundle backend/scheduler/jobs/daily.outageupdate.ts dist/daily.outageupdate.ts && deno bundle backend/scheduler/jobs/daily.priceupdate.ts dist/daily.priceupdate.ts && deno bundle backend/scheduler/jobs/hourly.consumptionupdate.ts dist/hourly.consumptionupdate.ts && deno bundle backend/scheduler/jobs/hourly.productionupdate.ts dist/hourly.productionupdate.ts", "dev": "deno run -A --unstable-ffi --watch=static/,routes/ dev.ts --no-schedules", @@ -6,19 +7,23 @@ "precommit": "deno fmt --check && deno lint && deno check main.ts && deno test", "prod": "deno run -A --unstable-ffi main.ts", "update-deps": "deno run --allow-read=. --allow-write=. --allow-net https://deno.land/x/udd/main.ts --dry-run deno.json", - "update-fresh": "deno run -A -r https://fresh.deno.dev/update .", + "update-fresh": "deno run -A -r jsr:@fresh/update .", "preview": "deno run -A main.ts" }, "fmt": { "exclude": ["components/", "islands/"], "lineWidth": 150 }, "compilerOptions": { - "jsx": "react-jsx", + "lib": ["dom", "dom.asynciterable", "dom.iterable", "deno.ns"], + "jsx": "precompile", "jsxImportSource": "preact", - "types": ["https://cdn.jsdelivr.net/npm/apexcharts@3.36.3/types/apexcharts.d.ts"] + "jsxPrecompileSkipElements": ["a", "img", "source", "body", "html", "head", "title", "meta", "script", "link", "style", "base", "noscript", "template"] }, "imports": { - "$fresh/": "https://deno.land/x/fresh@1.6.8/", - "@preact/signals": "https://esm.sh/*@preact/signals@1.2.2", - "@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.1", + "fresh": "jsr:@fresh/core@^2.1.3", + "fresh/server": "jsr:@fresh/core@^2.1.3/server", + "fresh/dev": "jsr:@fresh/core@^2.1.3/dev", + "fresh/runtime": "jsr:@fresh/core@^2.1.3/runtime", + "@preact/signals": "npm:@preact/signals@^2.3.2", + "@preact/signals-core": "npm:@preact/signals-core@^1.8.0", "@pup/telemetry": "jsr:@pup/telemetry@^1.0.7", "backend/": "./backend/", "components/": "./components/", @@ -29,9 +34,9 @@ "https://deno.land/x/glob_filter@1.0.0/mod.ts": "https://deno.land/x/glob_filter@1.0.1/mod.ts", "islands/": "./islands/", "localekit_fresh": "https://deno.land/x/localekit_fresh@0.5.2/mod.ts", - "preact": "https://esm.sh/preact@10.19.6", - "preact-render-to-string": "https://esm.sh/*preact-render-to-string@6.2.2", - "preact/": "https://esm.sh/preact@10.19.6/", + "preact": "npm:preact@^10.27.2", + "preact-render-to-string": "npm:preact-render-to-string@^6.5.15", + "preact/": "npm:preact@^10.27.2/", "routes/": "./routes/", "sqlite3": "https://deno.land/x/sqlite3@0.11.1/mod.ts", "std/path/mod.ts": "jsr:@std/path", diff --git a/dev.ts b/dev.ts index 2d85d6c..015bc29 100644 --- a/dev.ts +++ b/dev.ts @@ -1,5 +1,5 @@ #!/usr/bin/env -S deno run -A --watch=static/,routes/ -import dev from "$fresh/dev.ts"; +import dev from "fresh/dev"; await dev(import.meta.url, "./main.ts"); diff --git a/fresh.gen.ts b/fresh.gen.ts index b671338..93a64dc 100644 --- a/fresh.gen.ts +++ b/fresh.gen.ts @@ -21,7 +21,7 @@ import * as $CustomIsland from "./islands/CustomIsland.tsx"; import * as $HassIsland from "./islands/HassIsland.tsx"; import * as $HelpIsland from "./islands/HelpIsland.tsx"; import * as $IndexIsland from "./islands/IndexIsland.tsx"; -import { type Manifest } from "$fresh/server.ts"; +import { type Manifest } from "fresh/server"; const manifest = { routes: { diff --git a/islands/AreaIsland.tsx b/islands/AreaIsland.tsx index 3f170bd..02c213c 100644 --- a/islands/AreaIsland.tsx +++ b/islands/AreaIsland.tsx @@ -1,4 +1,4 @@ -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { useCallback, useEffect, useState } from "preact/hooks"; import { Cron } from "croner"; diff --git a/islands/CountryIsland.tsx b/islands/CountryIsland.tsx index 04edae5..0851dcd 100644 --- a/islands/CountryIsland.tsx +++ b/islands/CountryIsland.tsx @@ -1,4 +1,4 @@ -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { useCallback, useEffect, useState } from "preact/hooks"; import { Cron } from "croner"; diff --git a/islands/CustomIsland.tsx b/islands/CustomIsland.tsx index 4aed0e9..62cd2f5 100644 --- a/islands/CustomIsland.tsx +++ b/islands/CustomIsland.tsx @@ -1,6 +1,6 @@ import FilteredTable from "components/FilteredTable.tsx"; import { useCallback, useState } from "preact/hooks"; -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import Navbar from "components/layout/NavBar.tsx"; import Sidebar from "components/layout/Sidebar.tsx"; import { preferences } from "config/preferences.js"; diff --git a/islands/HassIsland.tsx b/islands/HassIsland.tsx index f814dfb..78bc638 100644 --- a/islands/HassIsland.tsx +++ b/islands/HassIsland.tsx @@ -1,6 +1,6 @@ // @deno-types="../types/hljs.d.ts" -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { useEffect, useState } from "preact/hooks"; import Navbar from "components/layout/NavBar.tsx"; diff --git a/islands/HelpIsland.tsx b/islands/HelpIsland.tsx index 11fa845..5897c95 100644 --- a/islands/HelpIsland.tsx +++ b/islands/HelpIsland.tsx @@ -1,4 +1,4 @@ -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { useState } from "preact/hooks"; import { preferences } from "config/preferences.js"; diff --git a/islands/IndexIsland.tsx b/islands/IndexIsland.tsx index dfcd94a..d5f98c3 100644 --- a/islands/IndexIsland.tsx +++ b/islands/IndexIsland.tsx @@ -1,4 +1,4 @@ -import { PageProps } from "$fresh/server.ts"; +import { PageProps } from "fresh/server"; import { useCallback, useState, useEffect } from "preact/hooks"; import { preferences } from "config/preferences.js"; diff --git a/main.ts b/main.ts index 412db83..a1c66ec 100644 --- a/main.ts +++ b/main.ts @@ -2,7 +2,7 @@ import { PupTelemetry } from "@pup/telemetry"; import languagePlugin from "localekit_fresh"; import languageConfig from "config/translate.config.ts"; -import { start } from "$fresh/server.ts"; +import { start } from "fresh/server"; import manifest from "./fresh.gen.ts"; import { langFromUrl } from "utils/common.ts"; import { log, setLevel } from "./utils/log.ts"; diff --git a/routes/[country]/[area].tsx b/routes/[country]/[area].tsx index 3ee77dd..e274b7f 100644 --- a/routes/[country]/[area].tsx +++ b/routes/[country]/[area].tsx @@ -1,4 +1,4 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import SwHead from "components/layout/SwHead.tsx"; import ElomradeIsland from "islands/AreaIsland.tsx"; import { diff --git a/routes/[country]/index.tsx b/routes/[country]/index.tsx index 69510e8..06f6e3a 100644 --- a/routes/[country]/index.tsx +++ b/routes/[country]/index.tsx @@ -1,4 +1,4 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import SwHead from "components/layout/SwHead.tsx"; import CountryIsland from "islands/CountryIsland.tsx"; import { diff --git a/routes/_app.tsx b/routes/_app.tsx index 62be6d1..f18fde5 100644 --- a/routes/_app.tsx +++ b/routes/_app.tsx @@ -1,4 +1,4 @@ -import { AppProps } from "$fresh/server.ts"; +import { AppProps } from "fresh/server"; export default function App({ Component }: AppProps) { return ( diff --git a/routes/_middleware.ts b/routes/_middleware.ts index 81dfad6..f3cbfec 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -1,5 +1,5 @@ // routes/_middleware.ts -import { MiddlewareHandlerContext } from "$fresh/server.ts"; +import { MiddlewareHandlerContext } from "fresh/server"; import { langFromUrl } from "utils/common.ts"; export const handler = [ diff --git a/routes/api/v2/hass.tsx b/routes/api/v2/hass.tsx index 66642ba..8892747 100644 --- a/routes/api/v2/hass.tsx +++ b/routes/api/v2/hass.tsx @@ -1,4 +1,4 @@ -import { Handlers } from "$fresh/server.ts"; +import { Handlers } from "fresh/server"; import { GetDataDay, SpotApiRow } from "backend/db/index.ts"; import { avgPrice, maxPrice, minPrice, nowPrice, processPrice } from "utils/price.ts"; import { intervalForArea } from "utils/common.ts"; diff --git a/routes/api/v2/spot.tsx b/routes/api/v2/spot.tsx index 35bd048..88dc05a 100644 --- a/routes/api/v2/spot.tsx +++ b/routes/api/v2/spot.tsx @@ -1,4 +1,4 @@ -import { Handlers } from "$fresh/server.ts"; +import { Handlers } from "fresh/server"; import { GetSpotprice } from "backend/db/index.ts"; import { intervalForArea } from "utils/common.ts"; import { sqlGroupBy } from "backend/db/sql/index.ts"; diff --git a/routes/custom.tsx b/routes/custom.tsx index 985cf8f..7ecf1fd 100644 --- a/routes/custom.tsx +++ b/routes/custom.tsx @@ -1,4 +1,4 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import SwHead from "components/layout/SwHead.tsx"; import CustomIsland from "islands/CustomIsland.tsx"; import { GetExchangeRates } from "backend/db/index.ts"; diff --git a/routes/help.tsx b/routes/help.tsx index 10edd11..5579bef 100644 --- a/routes/help.tsx +++ b/routes/help.tsx @@ -1,5 +1,5 @@ import SwHead from "components/layout/SwHead.tsx"; -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import HelpIsland from "islands/HelpIsland.tsx"; import { BasePageProps } from "utils/common.ts"; import { ExchangeRateResult, GetExchangeRates } from "../backend/db/index.ts"; diff --git a/routes/homeassistant.tsx b/routes/homeassistant.tsx index d5d989a..ef63848 100644 --- a/routes/homeassistant.tsx +++ b/routes/homeassistant.tsx @@ -1,5 +1,5 @@ import SwHead from "components/layout/SwHead.tsx"; -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import HassIsland from "islands/HassIsland.tsx"; import { BasePageProps } from "utils/common.ts"; import { ExchangeRateResult, GetExchangeRates } from "backend/db/index.ts"; diff --git a/routes/index.tsx b/routes/index.tsx index b6cebb5..5b4ff43 100644 --- a/routes/index.tsx +++ b/routes/index.tsx @@ -1,4 +1,4 @@ -import { Handlers, PageProps } from "$fresh/server.ts"; +import { Handlers, PageProps } from "fresh/server"; import SwHead from "components/layout/SwHead.tsx"; import IndexIsland from "islands/IndexIsland.tsx"; import { diff --git a/routes/sitemap.xml.ts b/routes/sitemap.xml.ts index f34e26e..561d2a7 100644 --- a/routes/sitemap.xml.ts +++ b/routes/sitemap.xml.ts @@ -1,4 +1,4 @@ -import { Handlers } from "$fresh/server.ts"; +import { Handlers } from "fresh/server"; import { SitemapContext } from "fresh_seo"; import { countries } from "config/countries.ts"; import manifest from "../fresh.gen.ts";