From e4aecdd9d455fe22876fa5c56eb3ed340613d811 Mon Sep 17 00:00:00 2001 From: L <6723574+louisgv@users.noreply.github.com> Date: Thu, 9 Mar 2023 12:52:23 -0600 Subject: [PATCH] fix(parcel-core): only allow client-side env to be included (#493) --- cli/create-plasmo/package.json | 2 +- cli/plasmo/package.json | 3 +- .../features/helpers/create-parcel-bundler.ts | 5 +- examples | 2 +- packages/parcel-config/package.json | 2 +- packages/parcel-core/.gitignore | 3 + packages/parcel-core/package.json | 49 ++ packages/parcel-core/src/index.ts | 437 ++++++++++++++++++ packages/parcel-core/src/resolve-options.ts | 221 +++++++++ packages/parcel-core/src/types.ts | 3 + packages/parcel-core/tsconfig.json | 5 + packages/parcel-core/tsup.config.ts | 5 + .../parcel-transformer-manifest/package.json | 2 +- .../parcel-transformer-manifest/src/schema.ts | 10 + packages/rps | 2 +- pnpm-lock.yaml | 59 ++- 16 files changed, 800 insertions(+), 10 deletions(-) create mode 100644 packages/parcel-core/.gitignore create mode 100644 packages/parcel-core/package.json create mode 100644 packages/parcel-core/src/index.ts create mode 100644 packages/parcel-core/src/resolve-options.ts create mode 100644 packages/parcel-core/src/types.ts create mode 100644 packages/parcel-core/tsconfig.json create mode 100644 packages/parcel-core/tsup.config.ts diff --git a/cli/create-plasmo/package.json b/cli/create-plasmo/package.json index 4287030ed..a4b5c09d3 100644 --- a/cli/create-plasmo/package.json +++ b/cli/create-plasmo/package.json @@ -1,6 +1,6 @@ { "name": "create-plasmo", - "version": "0.66.0", + "version": "0.67.0", "description": "Create Plasmo Framework Browser Extension", "main": "dist/index.js", "bin": "bin/index.mjs", diff --git a/cli/plasmo/package.json b/cli/plasmo/package.json index de67acac3..ee24f91fc 100644 --- a/cli/plasmo/package.json +++ b/cli/plasmo/package.json @@ -1,6 +1,6 @@ { "name": "plasmo", - "version": "0.66.0", + "version": "0.67.0", "description": "The Plasmo Platform CLI", "main": "dist/index.js", "types": "dist/type.d.ts", @@ -41,6 +41,7 @@ "@parcel/watcher": "2.1.0", "@plasmohq/init": "workspace:*", "@plasmohq/parcel-config": "workspace:*", + "@plasmohq/parcel-core": "workspace:*", "archiver": "5.3.1", "buffer": "6.0.3", "chalk": "5.2.0", diff --git a/cli/plasmo/src/features/helpers/create-parcel-bundler.ts b/cli/plasmo/src/features/helpers/create-parcel-bundler.ts index 3e6237447..436fb24a5 100644 --- a/cli/plasmo/src/features/helpers/create-parcel-bundler.ts +++ b/cli/plasmo/src/features/helpers/create-parcel-bundler.ts @@ -1,4 +1,3 @@ -import { Parcel } from "@parcel/core" import ParcelFS from "@parcel/fs" import ParcelPM from "@parcel/package-manager" import { emptyDir, ensureDir, readJson, writeJson } from "fs-extra" @@ -6,12 +5,12 @@ import { dirname, join, resolve } from "path" import { hasFlag } from "@plasmo/utils/flags" +import { Parcel, ParcelOptions } from "@plasmohq/parcel-core" + import type { PlasmoManifest } from "~features/manifest-factory/base" import { getPackageManager } from "./package-manager" -type ParcelOptions = Partial[0]> - const PackageInstallerMap = { npm: ParcelPM.Npm, yarn: ParcelPM.Yarn, diff --git a/examples b/examples index 8e6b32258..d6c05e08a 160000 --- a/examples +++ b/examples @@ -1 +1 @@ -Subproject commit 8e6b32258a4e032387a27d6b17d7daff46015940 +Subproject commit d6c05e08a0725050340314eb1dd7b7c42ad633fc diff --git a/packages/parcel-config/package.json b/packages/parcel-config/package.json index cc4d3235a..5da1639c2 100644 --- a/packages/parcel-config/package.json +++ b/packages/parcel-config/package.json @@ -1,6 +1,6 @@ { "name": "@plasmohq/parcel-config", - "version": "0.32.1", + "version": "0.32.2", "license": "MIT", "repository": { "type": "git", diff --git a/packages/parcel-core/.gitignore b/packages/parcel-core/.gitignore new file mode 100644 index 000000000..c7df64ac6 --- /dev/null +++ b/packages/parcel-core/.gitignore @@ -0,0 +1,3 @@ +node_modules + +dist/ \ No newline at end of file diff --git a/packages/parcel-core/package.json b/packages/parcel-core/package.json new file mode 100644 index 000000000..32bf77a39 --- /dev/null +++ b/packages/parcel-core/package.json @@ -0,0 +1,49 @@ +{ + "name": "@plasmohq/parcel-core", + "version": "0.0.0", + "description": "Plasmo Parcel Core Fork", + "files": [ + "dist" + ], + "main": "dist/index.js", + "types": "src/types.ts", + "scripts": { + "prepublishOnly": "pnpm build", + "build": "tsup --minify --clean", + "dev": "tsup --sourcemap --watch" + }, + "author": "Plasmo Corp. ", + "homepage": "https://docs.plasmo.com/", + "engines": { + "parcel": ">= 2.7.0" + }, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/PlasmoHQ/plasmo.git" + }, + "devDependencies": { + "@plasmo/config": "workspace:*", + "@plasmo/utils": "workspace:*", + "@parcel/types": "2.8.3", + "tsup": "6.6.3" + }, + "dependencies": { + "@parcel/core": "2.8.3", + "@parcel/cache": "2.8.3", + "@parcel/diagnostic": "2.8.3", + "@parcel/events": "2.8.3", + "@parcel/fs": "2.8.3", + "@parcel/graph": "2.8.3", + "@parcel/hash": "2.8.3", + "@parcel/logger": "2.8.3", + "@parcel/package-manager": "2.8.3", + "@parcel/plugin": "2.8.3", + "@parcel/source-map": "2.1.1", + "@parcel/types": "2.8.3", + "@parcel/utils": "2.8.3", + "@parcel/workers": "2.8.3", + "abortcontroller-polyfill": "1.7.5", + "nullthrows": "1.1.1" + } +} diff --git a/packages/parcel-core/src/index.ts b/packages/parcel-core/src/index.ts new file mode 100644 index 000000000..46a07d4a6 --- /dev/null +++ b/packages/parcel-core/src/index.ts @@ -0,0 +1,437 @@ +/** + * Forked from https://github.com/parcel-bundler/parcel/blob/19fe7ff00f28f44300fe803c4e594b9fc02b25ad/packages/core/core/src/Parcel.js + * MIT License + */ + +import { createWorkerFarm } from "@parcel/core" +import ParcelConfig from "@parcel/core/lib/ParcelConfig" +import ReporterRunner from "@parcel/core/lib/ReporterRunner" +import RequestTracker, { + getWatcherOptions, + requestGraphEdgeTypes +} from "@parcel/core/lib/RequestTracker" +import dumpGraphToGraphViz from "@parcel/core/lib/dumpGraphToGraphViz" +import { toProjectPath } from "@parcel/core/lib/projectPath" +import { assetFromValue } from "@parcel/core/lib/public/Asset" +import { PackagedBundle } from "@parcel/core/lib/public/Bundle" +import BundleGraph from "@parcel/core/lib/public/BundleGraph" +import createParcelBuildRequest from "@parcel/core/lib/requests/ParcelBuildRequest" +import { loadParcelConfig } from "@parcel/core/lib/requests/ParcelConfigRequest" +import createValidationRequest from "@parcel/core/lib/requests/ValidationRequest" +import { + BuildAbortError, + registerCoreWithSerializer +} from "@parcel/core/lib/utils" +import type { Diagnostic } from "@parcel/diagnostic" +import ThrowableDiagnostic, { anyToDiagnostic } from "@parcel/diagnostic" +import { ValueEmitter } from "@parcel/events" +import { Disposable } from "@parcel/events" +import { init as initHash } from "@parcel/hash" +import logger from "@parcel/logger" +import { init as initSourcemaps } from "@parcel/source-map" +import type { + AsyncSubscription, + BuildEvent, + BuildSuccessEvent, + PackagedBundle as IPackagedBundle, + InitialParcelOptions +} from "@parcel/types" +import { PromiseQueue } from "@parcel/utils" +// eslint-disable-next-line no-unused-vars +import { AbortController } from "abortcontroller-polyfill/dist/cjs-ponyfill" +import invariant from "assert" +import nullthrows from "nullthrows" + +import { resolveOptions } from "./resolve-options" + +registerCoreWithSerializer() + +export const INTERNAL_TRANSFORM: symbol = Symbol("internal_transform") +export const INTERNAL_RESOLVE: symbol = Symbol("internal_resolve") + +type SharedReference = number + +export class Parcel { + #requestTracker: RequestTracker + #config: ParcelConfig + #farm + #initialized = false + #disposable: Disposable + #initialOptions: InitialParcelOptions + #reporterRunner: ReporterRunner + #resolvedOptions = null + #optionsRef: SharedReference + #watchAbortController /*: AbortController*/ + #watchQueue = new PromiseQueue({ + maxConcurrent: 1 + }) + + #watchEvents: ValueEmitter< + | { + error: Error + buildEvent?: void + } + | { + buildEvent: BuildEvent + error?: void + } + > + + #watcherSubscription: AsyncSubscription + #watcherCount = 0 + #requestedAssetIds: Set = new Set() + + isProfiling /*: boolean */ + + constructor(options: InitialParcelOptions) { + this.#initialOptions = options + } + + async _init(): Promise { + if (this.#initialized) { + return + } + + await initSourcemaps + await initHash + + let resolvedOptions = await resolveOptions(this.#initialOptions) + this.#resolvedOptions = resolvedOptions + let { config } = await loadParcelConfig(resolvedOptions) + this.#config = new ParcelConfig(config, resolvedOptions) + + if (this.#initialOptions.workerFarm) { + if (this.#initialOptions.workerFarm["ending"]) { + throw new Error("Supplied WorkerFarm is ending") + } + this.#farm = this.#initialOptions.workerFarm + } else { + this.#farm = createWorkerFarm({ + shouldPatchConsole: resolvedOptions.shouldPatchConsole + }) + } + + // @ts-ignore QUIRK: upstream def is outdated: + await resolvedOptions.cache.ensure() + + let { dispose: disposeOptions, ref: optionsRef } = + await this.#farm.createSharedReference(resolvedOptions, false) + this.#optionsRef = optionsRef + + this.#disposable = new Disposable() + if (this.#initialOptions.workerFarm) { + // If we don't own the farm, dispose of only these references when + // Parcel ends. + this.#disposable.add(disposeOptions) + } else { + // Otherwise, when shutting down, end the entire farm we created. + this.#disposable.add(() => this.#farm.end()) + } + + this.#watchEvents = new ValueEmitter() + this.#disposable.add(() => this.#watchEvents.dispose()) + + this.#requestTracker = await RequestTracker.init({ + farm: this.#farm, + options: resolvedOptions + }) + + this.#reporterRunner = new ReporterRunner({ + config: this.#config, + options: resolvedOptions, + workerFarm: this.#farm + }) + this.#disposable.add(this.#reporterRunner) + + this.#initialized = true + } + + async run(): Promise { + let startTime = Date.now() + if (!this.#initialized) { + await this._init() + } + + let result = await this._build({ startTime }) + await this._end() + + if (result.type === "buildFailure") { + throw new BuildError(result.diagnostics) + } + + return result + } + + async _end(): Promise { + this.#initialized = false + + await Promise.all([ + this.#disposable.dispose(), + await this.#requestTracker.writeToCache() + ]) + } + + async _startNextBuild() { + this.#watchAbortController = new AbortController() + await this.#farm.callAllWorkers("clearConfigCache", []) + + try { + let buildEvent = await this._build({ + signal: this.#watchAbortController.signal + }) + + this.#watchEvents.emit({ + buildEvent + }) + + return buildEvent + } catch (err) { + // Ignore BuildAbortErrors and only emit critical errors. + if (!(err instanceof BuildAbortError)) { + throw err + } + } + } + + async watch( + cb?: (err: Error, buildEvent?: BuildEvent) => any + ): Promise { + if (!this.#initialized) { + await this._init() + } + + let watchEventsDisposable + if (cb) { + watchEventsDisposable = this.#watchEvents.addListener( + ({ error, buildEvent }) => cb(error, buildEvent) + ) + } + + if (this.#watcherCount === 0) { + this.#watcherSubscription = await this._getWatcherSubscription() + await this.#reporterRunner.report({ type: "watchStart" }) + + // Kick off a first build, but don't await its results. Its results will + // be provided to the callback. + this.#watchQueue.add(() => this._startNextBuild()) + this.#watchQueue.run() + } + + this.#watcherCount++ + + let unsubscribePromise + const unsubscribe = async () => { + if (watchEventsDisposable) { + watchEventsDisposable.dispose() + } + + this.#watcherCount-- + if (this.#watcherCount === 0) { + await nullthrows(this.#watcherSubscription).unsubscribe() + this.#watcherSubscription = null + await this.#reporterRunner.report({ type: "watchEnd" }) + this.#watchAbortController.abort() + await this.#watchQueue.run() + await this._end() + } + } + + return { + unsubscribe() { + if (unsubscribePromise == null) { + unsubscribePromise = unsubscribe() + } + + return unsubscribePromise + } + } + } + + async _build({ + signal = null, + startTime = Date.now() + } = {}): Promise { + this.#requestTracker.setSignal(signal) + let options = nullthrows(this.#resolvedOptions) + try { + if (options.shouldProfile) { + await this.startProfiling() + } + this.#reporterRunner.report({ + type: "buildStart" + }) + + this.#requestTracker.graph.invalidateOnBuildNodes() + + let request = createParcelBuildRequest({ + optionsRef: this.#optionsRef, + requestedAssetIds: this.#requestedAssetIds, + signal + }) + + let { bundleGraph, bundleInfo, changedAssets, assetRequests } = + await this.#requestTracker.runRequest(request, { force: true }) + + this.#requestedAssetIds.clear() + + dumpGraphToGraphViz( + // $FlowFixMe + this.#requestTracker.graph, + "RequestGraph", + requestGraphEdgeTypes + ) + + let event = { + type: "buildSuccess" as const, + changedAssets: new Map( + Array.from(changedAssets).map(([id, asset]) => [ + id, + assetFromValue(asset, options) + ]) + ), + bundleGraph: new BundleGraph( + bundleGraph, + (bundle, bundleGraph, options) => + PackagedBundle.getWithInfo( + bundle, + bundleGraph, + options, + bundleInfo.get(bundle.id) + ), + options + ), + buildTime: Date.now() - startTime, + requestBundle: async (bundle) => { + let bundleNode = bundleGraph._graph.getNodeByContentKey(bundle.id) + invariant(bundleNode?.type === "bundle", "Bundle does not exist") + + if (!bundleNode.value.isPlaceholder) { + // Nothing to do. + return { + type: "buildSuccess", + changedAssets: new Map(), + bundleGraph: event.bundleGraph, + buildTime: 0, + requestBundle: event.requestBundle + } + } + + for (let assetId of bundleNode.value.entryAssetIds) { + this.#requestedAssetIds.add(assetId) + } + + if (this.#watchQueue.getNumWaiting() === 0) { + if (this.#watchAbortController) { + this.#watchAbortController.abort() + } + + this.#watchQueue.add(() => this._startNextBuild()) + } + + let results = await this.#watchQueue.run() + let result = results.filter(Boolean).pop() + if (result.type === "buildFailure") { + throw new BuildError(result.diagnostics) + } + + return result + } + } + + await this.#reporterRunner.report(event) + await this.#requestTracker.runRequest( + createValidationRequest({ + optionsRef: this.#optionsRef, + assetRequests + }), + { force: assetRequests.length > 0 } + ) + return event + } catch (e) { + if (e instanceof BuildAbortError) { + throw e + } + + let diagnostic = anyToDiagnostic(e) + let event = { + type: "buildFailure" as const, + diagnostics: Array.isArray(diagnostic) ? diagnostic : [diagnostic] + } + + await this.#reporterRunner.report(event) + + return event + } finally { + if (this.isProfiling) { + await this.stopProfiling() + } + + await this.#farm.callAllWorkers("clearConfigCache", []) + } + } + + async _getWatcherSubscription(): Promise { + invariant(this.#watcherSubscription == null) + + let resolvedOptions = nullthrows(this.#resolvedOptions) + let opts = getWatcherOptions(resolvedOptions) + let sub = await resolvedOptions.inputFS.watch( + resolvedOptions.projectRoot, + (err, events) => { + if (err) { + this.#watchEvents.emit({ error: err }) + return + } + + let isInvalid = this.#requestTracker.respondToFSEvents( + events.map((e) => ({ + type: e.type, + path: toProjectPath(resolvedOptions.projectRoot, e.path) + })) + ) + if (isInvalid && this.#watchQueue.getNumWaiting() === 0) { + if (this.#watchAbortController) { + this.#watchAbortController.abort() + } + + this.#watchQueue.add(() => this._startNextBuild()) + this.#watchQueue.run() + } + }, + opts + ) + return { unsubscribe: () => sub.unsubscribe() } + } + + async startProfiling(): Promise { + if (this.isProfiling) { + throw new Error("Parcel is already profiling") + } + + logger.info({ origin: "@parcel/core", message: "Starting profiling..." }) + this.isProfiling = true + await this.#farm.startProfile() + } + + stopProfiling(): Promise { + if (!this.isProfiling) { + throw new Error("Parcel is not profiling") + } + + logger.info({ origin: "@parcel/core", message: "Stopping profiling..." }) + this.isProfiling = false + return this.#farm.endProfile() + } + + takeHeapSnapshot(): Promise { + logger.info({ origin: "@parcel/core", message: "Taking heap snapshot..." }) + return this.#farm.takeHeapSnapshot() + } +} + +class BuildError extends ThrowableDiagnostic { + constructor(diagnostic: Array | Diagnostic) { + super({ diagnostic }) + this.name = "BuildError" + } +} diff --git a/packages/parcel-core/src/resolve-options.ts b/packages/parcel-core/src/resolve-options.ts new file mode 100644 index 000000000..a097196cf --- /dev/null +++ b/packages/parcel-core/src/resolve-options.ts @@ -0,0 +1,221 @@ +/** + * Based on https://github.com/parcel-bundler/parcel/blob/v2/packages/core/core/src/resolveOptions.js + * MIT License + */ + +import { FSCache, LMDBCache } from "@parcel/cache" +import { toProjectPath } from "@parcel/core/lib/projectPath" +import { getResolveFrom } from "@parcel/core/lib/requests/ParcelConfigRequest" +import type { FileSystem } from "@parcel/fs" +import { NodeFS } from "@parcel/fs" +import { hashString } from "@parcel/hash" +import { NodePackageManager } from "@parcel/package-manager" +import type { + DependencySpecifier, + FilePath, + InitialParcelOptions, + InitialServerOptions +} from "@parcel/types" +import { getRootDir, isGlob, relativePath, resolveConfig } from "@parcel/utils" +import path from "path" + +// Default cache directory name +const LOCK_FILE_NAMES = ["yarn.lock", "package-lock.json", "pnpm-lock.yaml"] + +// Generate a unique instanceId, will change on every run of parcel +function generateInstanceId(entries: Array): string { + return hashString( + `${entries.join(",")}-${Date.now()}-${Math.round(Math.random() * 100)}` + ) +} + +export async function resolveOptions(initialOptions: InitialParcelOptions) { + let inputFS = initialOptions.inputFS || new NodeFS() + let outputFS = initialOptions.outputFS || new NodeFS() + let inputCwd = inputFS.cwd() + let outputCwd = outputFS.cwd() + let entries: Array + + if (initialOptions.entries == null || initialOptions.entries === "") { + entries = [] + } else if (Array.isArray(initialOptions.entries)) { + entries = initialOptions.entries.map((entry) => + path.resolve(inputCwd, entry) + ) + } else { + entries = [path.resolve(inputCwd, initialOptions.entries)] + } + + let shouldMakeEntryReferFolder = false + + if (entries.length === 1 && !isGlob(entries[0])) { + let [entry] = entries + + try { + shouldMakeEntryReferFolder = (await inputFS.stat(entry)).isDirectory() + } catch { + // ignore failing stat call + } + } + + // getRootDir treats the input as files, so getRootDir(["/home/user/myproject"]) returns "/home/user". + // Instead we need to make the the entry refer to some file inside the specified folders if entries refers to the directory. + let entryRoot = getRootDir( + shouldMakeEntryReferFolder ? [path.join(entries[0], "index")] : entries + ) + let projectRootFile = + (await resolveConfig( + inputFS, + path.join(entryRoot, "index"), + [...LOCK_FILE_NAMES, ".git", ".hg"], + path.parse(entryRoot).root + )) || path.join(inputCwd, "index") + // ? Should this just be rootDir + let projectRoot = path.dirname(projectRootFile) + let packageManager = + initialOptions.packageManager || + new NodePackageManager(inputFS, projectRoot) + + let cacheDir = path.resolve(outputCwd, initialOptions.cacheDir) + + let cache = + initialOptions.cache ?? + (outputFS instanceof NodeFS + ? new LMDBCache(cacheDir) + : // @ts-ignore QUIRK: upstream def is outdated + new FSCache(outputFS, cacheDir)) + + let mode = initialOptions.mode ?? "development" + let shouldOptimize = + initialOptions?.defaultTargetOptions?.shouldOptimize ?? + mode === "production" + let publicUrl = initialOptions?.defaultTargetOptions?.publicUrl ?? "/" + let distDir = + initialOptions?.defaultTargetOptions?.distDir != null + ? path.resolve(inputCwd, initialOptions?.defaultTargetOptions?.distDir) + : undefined + let shouldBuildLazily = initialOptions.shouldBuildLazily ?? false + let shouldContentHash = + initialOptions.shouldContentHash ?? initialOptions.mode === "production" + + if (shouldBuildLazily && shouldContentHash) { + throw new Error("Lazy bundling does not work with content hashing") + } + + let env = initialOptions.env + let port = determinePort(initialOptions.serveOptions, process.env.PORT) + + return { + config: getRelativeConfigSpecifier( + inputFS, + projectRoot, + initialOptions.config + ), + defaultConfig: getRelativeConfigSpecifier( + inputFS, + projectRoot, + initialOptions.defaultConfig + ), + shouldPatchConsole: initialOptions.shouldPatchConsole ?? false, + env, + mode, + shouldAutoInstall: initialOptions.shouldAutoInstall ?? false, + hmrOptions: initialOptions.hmrOptions ?? null, + shouldBuildLazily, + shouldBundleIncrementally: initialOptions.shouldBundleIncrementally ?? true, + shouldContentHash, + serveOptions: initialOptions.serveOptions + ? { + ...initialOptions.serveOptions, + distDir: distDir ?? path.join(outputCwd, "dist"), + port + } + : false, + shouldDisableCache: initialOptions.shouldDisableCache ?? false, + shouldProfile: initialOptions.shouldProfile ?? false, + cacheDir, + entries: entries.map((e) => toProjectPath(projectRoot, e)), + targets: initialOptions.targets, + logLevel: initialOptions.logLevel ?? "info", + projectRoot, + inputFS, + outputFS, + cache, + packageManager, + additionalReporters: + initialOptions.additionalReporters?.map( + ({ packageName, resolveFrom }) => ({ + packageName, + resolveFrom: toProjectPath(projectRoot, resolveFrom) + }) + ) ?? [], + instanceId: generateInstanceId(entries), + detailedReport: initialOptions.detailedReport, + defaultTargetOptions: { + shouldOptimize, + shouldScopeHoist: initialOptions?.defaultTargetOptions?.shouldScopeHoist, + sourceMaps: initialOptions?.defaultTargetOptions?.sourceMaps ?? true, + publicUrl, + ...(distDir != null + ? { + distDir: toProjectPath(projectRoot, distDir) + } + : { + /*::...null*/ + }), + engines: initialOptions?.defaultTargetOptions?.engines, + outputFormat: initialOptions?.defaultTargetOptions?.outputFormat, + isLibrary: initialOptions?.defaultTargetOptions?.isLibrary + } + } +} + +function getRelativeConfigSpecifier( + fs: FileSystem, + projectRoot: FilePath, + specifier: DependencySpecifier | null | undefined +) { + if (specifier == null) { + return undefined + } else if (path.isAbsolute(specifier)) { + let resolveFrom = getResolveFrom(fs, projectRoot) + let relative = relativePath(path.dirname(resolveFrom), specifier) + // If the config is outside the project root, use an absolute path so that if the project root + // moves the path still works. Otherwise, use a relative path so that the cache is portable. + return relative.startsWith("..") ? specifier : relative + } else { + return specifier + } +} + +function determinePort( + initialServerOptions: InitialServerOptions | false | void, + portInEnv: string | void, + defaultPort: number = 1234 +): number { + function parsePort(port: string) { + let parsedPort = Number(port) + + // return undefined if port number defined in .env is not valid integer + if (!Number.isInteger(parsedPort)) { + return undefined + } + + return parsedPort + } + + if (!initialServerOptions) { + return typeof portInEnv !== "undefined" + ? parsePort(portInEnv) ?? defaultPort + : defaultPort + } + + // if initialServerOptions.port is equal to defaultPort, then this means that port number is provided via PORT=~~~~ on cli. In this case, we should ignore port number defined in .env. + if (initialServerOptions.port !== defaultPort) { + return initialServerOptions.port + } + + return typeof portInEnv !== "undefined" + ? parsePort(portInEnv) ?? defaultPort + : defaultPort +} diff --git a/packages/parcel-core/src/types.ts b/packages/parcel-core/src/types.ts new file mode 100644 index 000000000..f1ac5093d --- /dev/null +++ b/packages/parcel-core/src/types.ts @@ -0,0 +1,3 @@ +export type { InitialParcelOptions as ParcelOptions } from "@parcel/types" + +export { Parcel } from "./index" diff --git a/packages/parcel-core/tsconfig.json b/packages/parcel-core/tsconfig.json new file mode 100644 index 000000000..baa127a20 --- /dev/null +++ b/packages/parcel-core/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "@plasmo/config/ts/cli", + "include": ["src/**/*.ts"], + "exclude": ["dist", "node_modules"] +} diff --git a/packages/parcel-core/tsup.config.ts b/packages/parcel-core/tsup.config.ts new file mode 100644 index 000000000..0a09924ec --- /dev/null +++ b/packages/parcel-core/tsup.config.ts @@ -0,0 +1,5 @@ +import { defineConfig } from "tsup" + +export default defineConfig({ + entry: ["src/index.ts"] +}) diff --git a/packages/parcel-transformer-manifest/package.json b/packages/parcel-transformer-manifest/package.json index 0a7f9b2a5..38102ffb5 100644 --- a/packages/parcel-transformer-manifest/package.json +++ b/packages/parcel-transformer-manifest/package.json @@ -1,6 +1,6 @@ { "name": "@plasmohq/parcel-transformer-manifest", - "version": "0.14.1", + "version": "0.14.2", "description": "Plasmo Parcel Transformer for Web Extension Manifest", "files": [ "dist", diff --git a/packages/parcel-transformer-manifest/src/schema.ts b/packages/parcel-transformer-manifest/src/schema.ts index c12f4b729..4832f8866 100644 --- a/packages/parcel-transformer-manifest/src/schema.ts +++ b/packages/parcel-transformer-manifest/src/schema.ts @@ -1,3 +1,11 @@ +/** + * Copyright (c) 2023 Plasmo Corp. (https://www.plasmo.com) and contributors + * MIT License + * + * Based on: https://github.com/parcel-bundler/parcel/blob/v2/packages/transformers/webextension/src/schema.js + * MIT License + */ + import type { FromSchema } from "json-schema-to-ts" import { @@ -22,6 +30,7 @@ const iconsSchema = { const actionProps = { // FF only browser_style: booleanSchema, + chrome_style: booleanSchema, // You can also have a raw string, but not in Edge, apparently... default_icon: { oneOf: [iconsSchema, stringSchema] @@ -277,6 +286,7 @@ const commonProps = { type: "object", properties: { browser_style: booleanSchema, + chrome_style: booleanSchema, open_in_tab: booleanSchema, page: stringSchema }, diff --git a/packages/rps b/packages/rps index 0d8d9111c..47d9224c0 160000 --- a/packages/rps +++ b/packages/rps @@ -1 +1 @@ -Subproject commit 0d8d9111cb938b19f101902df10ea59cbe04ba62 +Subproject commit 47d9224c031cdcb634a50a345b17eaa74c50dd7f diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fabe372fb..8c436a426 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -81,6 +81,7 @@ importers: '@plasmo/utils': workspace:* '@plasmohq/init': workspace:* '@plasmohq/parcel-config': workspace:* + '@plasmohq/parcel-core': workspace:* archiver: 5.3.1 buffer: 6.0.3 chalk: 5.2.0 @@ -113,6 +114,7 @@ importers: '@parcel/watcher': 2.1.0 '@plasmohq/init': link:../../packages/init '@plasmohq/parcel-config': link:../../packages/parcel-config + '@plasmohq/parcel-core': link:../../packages/parcel-core archiver: 5.3.1 buffer: 6.0.3 chalk: 5.2.0 @@ -1550,6 +1552,49 @@ importers: '@plasmohq/parcel-transformer-svelte3': link:../parcel-transformer-svelte3 '@plasmohq/parcel-transformer-vue3': link:../parcel-transformer-vue3 + packages/parcel-core: + specifiers: + '@parcel/cache': 2.8.3 + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + '@parcel/fs': 2.8.3 + '@parcel/graph': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/package-manager': 2.8.3 + '@parcel/plugin': 2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3 + '@plasmo/config': workspace:* + '@plasmo/utils': workspace:* + abortcontroller-polyfill: 1.7.5 + nullthrows: 1.1.1 + tsup: 6.6.3 + dependencies: + '@parcel/cache': 2.8.3_@parcel+core@2.8.3 + '@parcel/core': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + '@parcel/fs': 2.8.3_@parcel+core@2.8.3 + '@parcel/graph': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/package-manager': 2.8.3_@parcel+core@2.8.3 + '@parcel/plugin': 2.8.3_@parcel+core@2.8.3 + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.8.3_@parcel+core@2.8.3 + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3_@parcel+core@2.8.3 + abortcontroller-polyfill: 1.7.5 + nullthrows: 1.1.1 + devDependencies: + '@plasmo/config': link:../config + '@plasmo/utils': link:../utils + tsup: 6.6.3 + packages/parcel-namer-manifest: specifiers: '@parcel/core': 2.8.3 @@ -2116,6 +2161,9 @@ importers: packages/utils: specifiers: '@plasmo/config': workspace:* + email-addresses: 5.0.0 + dependencies: + email-addresses: 5.0.0 devDependencies: '@plasmo/config': link:../config @@ -5205,7 +5253,7 @@ packages: '@parcel/workers': 2.8.3_@parcel+core@2.8.3 abortcontroller-polyfill: 1.7.5 base-x: 3.0.9 - browserslist: 4.21.4 + browserslist: 4.21.5 clone: 2.1.2 dotenv: 7.0.0 dotenv-expand: 5.1.0 @@ -7924,6 +7972,7 @@ packages: electron-to-chromium: 1.4.284 node-releases: 2.0.7 update-browserslist-db: 1.0.10_browserslist@4.21.4 + dev: true /browserslist/4.21.5: resolution: {integrity: sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==} @@ -8092,6 +8141,7 @@ packages: /caniuse-lite/1.0.30001441: resolution: {integrity: sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==} + dev: true /caniuse-lite/1.0.30001460: resolution: {integrity: sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==} @@ -9076,6 +9126,7 @@ packages: /electron-to-chromium/1.4.284: resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==} + dev: true /electron-to-chromium/1.4.320: resolution: {integrity: sha512-h70iRscrNluMZPVICXYl5SSB+rBKo22XfuIS1ER0OQxQZpKTnFpuS6coj7wY9M/3trv7OR88rRMOlKmRvDty7Q==} @@ -9092,6 +9143,10 @@ packages: minimalistic-crypto-utils: 1.0.1 dev: true + /email-addresses/5.0.0: + resolution: {integrity: sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==} + dev: false + /emittery/0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} @@ -12955,6 +13010,7 @@ packages: /node-releases/2.0.7: resolution: {integrity: sha512-EJ3rzxL9pTWPjk5arA0s0dgXpnyiAbJDE6wHT62g7VsgrgQgmmZ+Ru++M1BFofncWja+Pnn3rEr3fieRySAdKQ==} + dev: true /node-stream-zip/1.15.0: resolution: {integrity: sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw==} @@ -16311,6 +16367,7 @@ packages: browserslist: 4.21.4 escalade: 3.1.1 picocolors: 1.0.0 + dev: true /update-browserslist-db/1.0.10_browserslist@4.21.5: resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}