Skip to main content
Module

x/aleph/server/helper.ts

The Full-stack Framework in Deno.
Go to Latest
File
import type { Plugin } from '../types.d.ts'import { dim, red, yellow } from 'https://deno.land/std@0.106.0/fmt/colors.ts'import { createHash } from 'https://deno.land/std@0.106.0/hash/mod.ts'import { dirname, basename, extname, join, relative } from 'https://deno.land/std@0.106.0/path/mod.ts'import { minDenoVersion } from '../shared/constants.ts'import { existsDir } from '../shared/fs.ts'import log from '../shared/log.ts'import util from '../shared/util.ts'import { SourceType } from '../compiler/mod.ts'import { VERSION } from '../version.ts'import { localProxy } from './localproxy.ts'
// inject browser navigator polyfillObject.assign((globalThis as any).navigator, { connection: { downlink: 10, effectiveType: '4g', onchange: null, rtt: 50, saveData: false, }, cookieEnabled: false, language: 'en', languages: ['en'], onLine: true, platform: Deno.build.os, userAgent: `Deno/${Deno.version.deno}`, vendor: 'Deno Land'})
export const encoder = new TextEncoder()export const decoder = new TextDecoder()export const moduleExclude = [ /(^|\/|\\)\./, /\.d\.ts$/i, /(\.|_)(test|spec|e2e)\.[a-z]+$/i]
const reLocalhostUrl = /^https?:\/\/(localhost|0\.0\.0\.0|127\.0\.0\.1)(\:|\/|$)/const reEndsWithVersion = /@\d+(\.\d+){0,2}(\-[a-z0-9]+(\.[a-z0-9]+)?)?$/
let _denoDir: string | null = nulllet _localProxy = false
export function checkDenoVersion() { const [currentMajor, currentMinor, currentPatch] = Deno.version.deno.split('.').map(p => parseInt(p)) const [major, minor, patch] = minDenoVersion.split('.').map(p => parseInt(p))
if (currentMajor > major) return if (currentMajor === major && currentMinor > minor) return if (currentMajor === major && currentMinor === minor && currentPatch >= patch) return
log.error(`Aleph.js needs Deno ${minDenoVersion}+, please upgrade Deno.`) Deno.exit(1)}
export function checkAlephDevEnv() { const v = Deno.env.get('ALEPH_DEV') if (v !== undefined && !_localProxy) { localProxy(Deno.cwd(), 2020) _localProxy = true }}
/** check whether it is a localhost url. */export function isLocalhostUrl(url: string): boolean { return reLocalhostUrl.test(url)}
/** get the deno cache dir. */export async function getDenoDir() { if (_denoDir !== null) { return _denoDir }
const p = Deno.run({ cmd: [Deno.execPath(), 'info', '--json'], stdout: 'piped', stderr: 'null' }) const output = decoder.decode(await p.output()) const { denoDir } = JSON.parse(output) p.close() if (denoDir === undefined || !await existsDir(denoDir)) { throw new Error(`can't find the deno dir`) } _denoDir = denoDir return denoDir}
/** get aleph pkg uri. */export function getAlephPkgUri() { const DEV_PORT = Deno.env.get('ALEPH_DEV_PORT') if (DEV_PORT) { return `http://localhost:${DEV_PORT}` } return `https://deno.land/x/aleph@v${VERSION}`}
/** load aleph plugin from `deno.land/x`, a aleph plugin should be named with `aleph_plugin_{name}`. */export async function loadPlugin(name: string, options?: any): Promise<Plugin> { let { default: p } = await import(`https://deno.land/x/aleph_plugin_${name}/plugin.ts`) if (util.isFunction(p)) { p = p(options) } if (p instanceof Promise) { p = await p } if (util.isFunction(p.setup)) { return p } return Promise.reject(new Error(`invalid plugin '${name}': missing 'setup' method`))}
/** get the relative path from `from` to `to`. */export function toRelativePath(from: string, to: string): string { const p = relative(from, to).replaceAll('\\', '/') if (!p.startsWith('.') && !p.startsWith('/')) { return './' + p } return p}
/** get source type by given url and content type. */export function getSourceType(url: string, contentType?: string): SourceType { if (util.isFilledString(contentType)) { switch (contentType.split(';')[0].trim()) { case 'application/javascript': case 'text/javascript': return SourceType.JS case 'text/jsx': return SourceType.JSX case 'text/typescript': if (url.endsWith('.tsx')) { return SourceType.TSX } return SourceType.TS case 'text/tsx': return SourceType.TSX case 'text/css': return SourceType.CSS } } switch (extname(url)) { case '.mjs': case '.js': return SourceType.JS case '.jsx': return SourceType.JSX case '.ts': return SourceType.TS case '.tsx': return SourceType.TSX case '.css': case '.pcss': case '.postcss': return SourceType.CSS } return SourceType.Unknown}
/** * fix remote import url to local * https://esm.sh/react.js?bundle -> /-/esm.sh/react.YnVuZGxl.js */export function toLocalPath(url: string): string { if (util.isLikelyHttpURL(url)) { let { hostname, pathname, port, protocol, search } = new URL(url) const isHttp = protocol === 'http:' if ((isHttp && port === '80') || (protocol === 'https:' && port === '443')) { port = '' } if (search !== '') { const a = util.splitPath(pathname) const basename = a.pop()! const realext = extname(basename) const ext = realext != "" && !basename.match(reEndsWithVersion) ? realext : "js" const search64 = util.btoaUrl(search.slice(1)) a.push(util.trimSuffix(basename, ext) + `.${search64}.` + ext) pathname = '/' + a.join('/') } return [ '/-/', (isHttp ? 'http_' : ''), hostname, (port ? '_' + port : ''), pathname ].join('') } return util.trimPrefix(url, 'file://')}
/** compute hash of the content */export function computeHash(content: string | Uint8Array, algorithm: 'md5' | 'sha1' = 'sha1'): string { return createHash(algorithm).update(content).toString()}
/** * coloring the bytes string * - dim: 0 - 1MB * - yellow: 1MB - 10MB * - red: > 10MB */export function formatBytesWithColor(bytes: number) { let cf = dim if (bytes > 10 << 20) { // 10MB cf = red } else if (bytes > 1 << 20) { // 1MB cf = yellow } return cf(util.formatBytes(bytes))}
export async function clearBuildCache(filename: string, ext = 'js') { const dir = dirname(filename) const hashname = basename(filename) const regHashExt = new RegExp(`\\.[0-9a-f]+\\.${ext}$`, 'i') if (ext && !regHashExt.test(hashname) || !await existsDir(dir)) { return }
const jsName = hashname.split('.').slice(0, -2).join('.') + '.' + ext for await (const entry of Deno.readDir(dir)) { if (entry.isFile && regHashExt.test(entry.name)) { const _jsName = entry.name.split('.').slice(0, -2).join('.') + '.' + ext if (_jsName === jsName && hashname !== entry.name) { await Deno.remove(join(dir, entry.name)) } } }}