From dde82e25a50e3ad4dcd503f539242dce5b557f0e Mon Sep 17 00:00:00 2001 From: ekzyis <27162016+ekzyis@users.noreply.github.com> Date: Sun, 24 Sep 2023 03:19:35 +0200 Subject: [PATCH] Convert worker to ESM (#500) * Convert worker to ESM To use ESM for the worker, I created a package.json file in worker/ with `{ type: "module" }` as its sole content. I then rewrote every import to use ESM syntax. I also tried to set `{ type: "module" }` in the root package.json file to also use ESM in next.config.js. However, this resulted in a weird problem: default imports were now getting imported as objects in this shape: `{ default: }`. Afaik, this should only be the case if you use "import * as foo from 'bar'" syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#default_import This is fixed by not using `{ type: "module" }` for some reason. However, then, next.config.js also doesn't support ESM import syntax anymore. The documentation says that if you want to use ESM, you can use next.config.mjs: https://nextjs.org/docs/pages/api-reference/next-config-js But I didn't want to use MJS extension since I don't have any experience with it. For example, not sure if it's good style to mix JS with MJS etc. So I kept the CJS import syntax there. * Ignore worker/ during linting I wasn't able to fix the following errors: /home/runner/work/stacker.news/stacker.news/worker/auction.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/auction.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/earn.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/earn.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/index.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/index.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/nostr.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/nostr.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/ots.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/ots.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/repin.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/repin.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/search.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/search.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/streak.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/streak.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/trust.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/trust.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/views.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/views.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) /home/runner/work/stacker.news/stacker.news/worker/wallet.js:0:0: Parsing error: No Babel config file detected for /home/runner/work/stacker.news/stacker.news/worker/wallet.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files. (null) I tried to tell babel where to find the babel config file (.babelrc), specifying the babel config in worker/package.json under "babel", using babel.config.json etc. to no avail. However, afaict, we don't need babel for the worker since it won't run in a browser. Babel is only used to transpile code to target browsers. But it still would be nice to lint the worker code with standard. But we can figure this out later. * Fix worker imports from lib/ and api/ This fixes the issue that we can't use `{ "type": "module" }` in the root package.json since it breaks the app with this error: app | TypeError: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20) app | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) app | LND GRPC connection successful app | - error pages/api/auth/[...nextauth].js (139:2) @ CredentialsProvider app | - error Error [TypeError]: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20) { app | digest: undefined app | } app | 137 | app | 138 | const providers = [ app | > 139 | CredentialsProvider({ app | | ^ app | 140 | id: 'lightning', app | 141 | name: 'Lightning', app | 142 | credentials: { app | TypeError: next_auth_providers_credentials__WEBPACK_IMPORTED_MODULE_2__ is not a function app | at eval (webpack-internal:///./pages/api/auth/[...nextauth].js:218:20) app | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) build but we need to tell the worker that the files are MJS, else we get this error: worker | file:///app/worker/wallet.js:3 worker | import { datePivot } from '../lib/time.js' worker | ^^^^^^^^^ worker | SyntaxError: Named export 'datePivot' not found. The requested module '../lib/time.js' is a CommonJS module, which may not support all module.exports as named exports. worker | CommonJS modules can always be imported via the default export, for example using: worker | worker | import pkg from '../lib/time.js'; worker | const { datePivot } = pkg; worker | worker | at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21) worker | at async ModuleJob.run (node:internal/modules/esm/module_job:190:5) worker | worker | Node.js v18.17.0 worker | worker exited with code 1 * Fix global not defined in browser context * Also ignore api/ and lib/ during linting I did not want to do this but I was not able to fix this error in any other way I tried: /home/ekzyis/programming/stacker.news/api/lnd/index.js:0:0: Parsing error: No Babel config file detected for /home/ekzyis/programming/stacker.news/api/lnd/index.js. Either disable config file checking with requ ireConfigFile: false, or configure Babel so that it can find the config files. (null) Did not want to look deeper into all this standard, eslint, babel configuration stuff ... --------- Co-authored-by: ekzyis Co-authored-by: Keyan <34140557+huumn@users.noreply.github.com> --- api/package.json | 3 + api/resolvers/serial.js | 8 +- api/search/index.js | 4 +- lib/apollo.js | 4 +- lib/constants.js | 102 ++++++++++----------- lib/package.json | 3 + lib/time.js | 12 +-- next.config.js | 2 +- package.json | 7 +- pages/_app.js | 6 +- pages/_document.js | 198 ++++++++++++++++++++-------------------- worker/auction.js | 6 +- worker/earn.js | 8 +- worker/index.js | 38 ++++---- worker/nostr.js | 8 +- worker/ots.js | 12 +-- worker/package.json | 3 + worker/repin.js | 4 +- worker/search.js | 12 +-- worker/streak.js | 6 +- worker/trust.js | 8 +- worker/views.js | 6 +- worker/wallet.js | 12 +-- 23 files changed, 229 insertions(+), 243 deletions(-) create mode 100644 api/package.json create mode 100644 lib/package.json create mode 100644 worker/package.json diff --git a/api/package.json b/api/package.json new file mode 100644 index 00000000..aead43de --- /dev/null +++ b/api/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/api/resolvers/serial.js b/api/resolvers/serial.js index 9971a3b9..1a4336bb 100644 --- a/api/resolvers/serial.js +++ b/api/resolvers/serial.js @@ -1,6 +1,6 @@ -const { GraphQLError } = require('graphql') -const retry = require('async-retry') -const Prisma = require('@prisma/client') +import { GraphQLError } from 'graphql' +import retry from 'async-retry' +import Prisma from '@prisma/client' async function serialize (models, ...calls) { return await retry(async bail => { @@ -56,4 +56,4 @@ async function serialize (models, ...calls) { }) } -module.exports = serialize +export default serialize diff --git a/api/search/index.js b/api/search/index.js index f2ddacd6..d6d1deb4 100644 --- a/api/search/index.js +++ b/api/search/index.js @@ -1,4 +1,4 @@ -const os = require('@opensearch-project/opensearch') +import os from '@opensearch-project/opensearch' const options = process.env.NODE_ENV === 'development' ? { node: 'http://localhost:9200' } @@ -12,4 +12,4 @@ const options = process.env.NODE_ENV === 'development' global.os = global.os || new os.Client(options) -module.exports = global.os +export default global.os diff --git a/lib/apollo.js b/lib/apollo.js index 573d5e8e..6f996fad 100644 --- a/lib/apollo.js +++ b/lib/apollo.js @@ -20,8 +20,8 @@ export default function getApolloClient () { if (SSR) { return getClient(`${process.env.SELF_URL}/api/graphql`) } else { - global.apolloClient ||= getClient('/api/graphql') - return global.apolloClient + window.apolloClient ||= getClient('/api/graphql') + return window.apolloClient } } diff --git a/lib/constants.js b/lib/constants.js index f6b9a036..4f325f63 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -1,57 +1,53 @@ // XXX this is temporary until we have so many subs they have // to be loaded from the server -const SUBS = ['bitcoin', 'nostr', 'tech', 'meta', 'jobs'] -const SUBS_NO_JOBS = SUBS.filter(s => s !== 'jobs') +export const SUBS = ['bitcoin', 'nostr', 'tech', 'meta', 'jobs'] +export const SUBS_NO_JOBS = SUBS.filter(s => s !== 'jobs') -module.exports = { - NOFOLLOW_LIMIT: 100, - BOOST_MIN: 5000, - UPLOAD_SIZE_MAX: 2 * 1024 * 1024, - IMAGE_PIXELS_MAX: 35000000, - UPLOAD_TYPES_ALLOW: [ - 'image/gif', - 'image/heic', - 'image/png', - 'image/jpeg', - 'image/webp' - ], - COMMENT_DEPTH_LIMIT: 10, - MAX_TITLE_LENGTH: 80, - MAX_POLL_CHOICE_LENGTH: 30, - ITEM_SPAM_INTERVAL: '10m', - ANON_ITEM_SPAM_INTERVAL: '0', - INV_PENDING_LIMIT: 10, - BALANCE_LIMIT_MSATS: 1000000000, // 1m sats - ANON_INV_PENDING_LIMIT: 100, - ANON_BALANCE_LIMIT_MSATS: 0, // disable - MAX_POLL_NUM_CHOICES: 10, - MIN_POLL_NUM_CHOICES: 2, - POLL_COST: 1, - ITEM_FILTER_THRESHOLD: 1.2, - DONT_LIKE_THIS_COST: 1, - COMMENT_TYPE_QUERY: ['comments', 'freebies', 'outlawed', 'borderland', 'all', 'bookmarks'], - SUBS, - SUBS_NO_JOBS, - USER_SORTS: ['stacked', 'spent', 'comments', 'posts', 'referrals'], - ITEM_SORTS: ['zaprank', 'comments', 'sats'], - WHENS: ['day', 'week', 'month', 'year', 'forever'], - ITEM_TYPES: context => { - const items = ['all', 'posts', 'comments', 'bounties', 'links', 'discussions', 'polls'] - if (!context) { - items.push('bios', 'jobs') - } - items.push('freebies') - if (context === 'user') { - items.push('jobs', 'bookmarks') - } - return items - }, - OLD_ITEM_DAYS: 3, - ANON_USER_ID: 27, - AD_USER_ID: 9, - ANON_POST_FEE: 1000, - ANON_COMMENT_FEE: 100, - SSR: typeof window === 'undefined', - MAX_FORWARDS: 5, - LNURLP_COMMENT_MAX_LENGTH: 1000 +export const NOFOLLOW_LIMIT = 100 +export const BOOST_MIN = 5000 +export const UPLOAD_SIZE_MAX = 2 * 1024 * 1024 +export const IMAGE_PIXELS_MAX = 35000000 +export const UPLOAD_TYPES_ALLOW = [ + 'image/gif', + 'image/heic', + 'image/png', + 'image/jpeg', + 'image/webp' +] +export const COMMENT_DEPTH_LIMIT = 10 +export const MAX_TITLE_LENGTH = 80 +export const MAX_POLL_CHOICE_LENGTH = 30 +export const ITEM_SPAM_INTERVAL = '10m' +export const ANON_ITEM_SPAM_INTERVAL = '0' +export const INV_PENDING_LIMIT = 10 +export const BALANCE_LIMIT_MSATS = 1000000000 // 1m sat +export const ANON_INV_PENDING_LIMIT = 100 +export const ANON_BALANCE_LIMIT_MSATS = 0 // disabl +export const MAX_POLL_NUM_CHOICES = 10 +export const MIN_POLL_NUM_CHOICES = 2 +export const POLL_COST = 1 +export const ITEM_FILTER_THRESHOLD = 1.2 +export const DONT_LIKE_THIS_COST = 1 +export const COMMENT_TYPE_QUERY = ['comments', 'freebies', 'outlawed', 'borderland', 'all', 'bookmarks'] +export const USER_SORTS = ['stacked', 'spent', 'comments', 'posts', 'referrals'] +export const ITEM_SORTS = ['zaprank', 'comments', 'sats'] +export const WHENS = ['day', 'week', 'month', 'year', 'forever'] +export const ITEM_TYPES = context => { + const items = ['all', 'posts', 'comments', 'bounties', 'links', 'discussions', 'polls'] + if (!context) { + items.push('bios', 'jobs') + } + items.push('freebies') + if (context === 'user') { + items.push('jobs', 'bookmarks') + } + return items } +export const OLD_ITEM_DAYS = 3 +export const ANON_USER_ID = 27 +export const AD_USER_ID = 9 +export const ANON_POST_FEE = 1000 +export const ANON_COMMENT_FEE = 100 +export const SSR = typeof window === 'undefined' +export const MAX_FORWARDS = 5 +export const LNURLP_COMMENT_MAX_LENGTH = 1000 diff --git a/lib/package.json b/lib/package.json new file mode 100644 index 00000000..aead43de --- /dev/null +++ b/lib/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/lib/time.js b/lib/time.js index e1443b54..45f95985 100644 --- a/lib/time.js +++ b/lib/time.js @@ -1,4 +1,4 @@ -function timeSince (timeStamp) { +export function timeSince (timeStamp) { const now = new Date() const secondsPast = (now.getTime() - timeStamp) / 1000 if (secondsPast < 60) { @@ -20,7 +20,7 @@ function timeSince (timeStamp) { return 'now' } -function datePivot (date, +export function datePivot (date, { years = 0, months = 0, days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 }) { return new Date( date.getFullYear() + years, @@ -33,9 +33,9 @@ function datePivot (date, ) } -const dayMonthYear = when => new Date(when).toISOString().slice(0, 10) +export const dayMonthYear = when => new Date(when).toISOString().slice(0, 10) -function timeLeft (timeStamp) { +export function timeLeft (timeStamp) { const now = new Date() const secondsPast = (timeStamp - now.getTime()) / 1000 @@ -57,6 +57,4 @@ function timeLeft (timeStamp) { } } -const sleep = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms)) - -module.exports = { timeSince, dayMonthYear, datePivot, timeLeft, sleep } +export const sleep = (ms) => new Promise((resolve, reject) => setTimeout(resolve, ms)) diff --git a/next.config.js b/next.config.js index 85b058f0..4e44b4a4 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,6 @@ const { withPlausibleProxy } = require('next-plausible') const { InjectManifest } = require('workbox-webpack-plugin') -const { generatePrecacheManifest } = require('./sw/build') +const { generatePrecacheManifest } = require('./sw/build.js') const isProd = process.env.NODE_ENV === 'production' const corsHeaders = [ diff --git a/package.json b/package.json index 529a2b01..eb9646f9 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,10 @@ "next" ], "ignore": [ - "**/spawn" + "**/spawn", + "**/worker", + "**/api", + "**/lib" ] }, "devDependencies": { @@ -114,4 +117,4 @@ "eslint": "^8.47.0", "standard": "^17.1.0" } -} +} \ No newline at end of file diff --git a/pages/_app.js b/pages/_app.js index 7d15c2ac..e41b9c18 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -2,7 +2,7 @@ import '../styles/globals.scss' import { ApolloProvider, gql } from '@apollo/client' import { MeProvider } from '../components/me' import PlausibleProvider from 'next-plausible' -import getApolloClient from '../lib/apollo' +import getApolloClient from '../lib/apollo.js' import { PriceProvider } from '../components/price' import { BlockHeightProvider } from '../components/block-height' import Head from 'next/head' @@ -34,7 +34,7 @@ function writeQuery (client, apollo, data) { } } -function MyApp ({ Component, pageProps: { ...props } }) { +export default function MyApp ({ Component, pageProps: { ...props } }) { const client = getApolloClient() const router = useRouter() @@ -111,5 +111,3 @@ function MyApp ({ Component, pageProps: { ...props } }) { ) } - -export default MyApp diff --git a/pages/_document.js b/pages/_document.js index 05234170..63a17a3e 100644 --- a/pages/_document.js +++ b/pages/_document.js @@ -1,18 +1,17 @@ -import Document, { Html, Head, Main, NextScript } from 'next/document' +import { Html, Head, Main, NextScript } from 'next/document' import Script from 'next/script' -class MyDocument extends Document { - render () { - return ( - - - - - - -