diff --git a/README.md b/README.md index fa43956c..306a7f5d 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,15 @@ Supported package managers: - `npm >=6` - `yarn >=1 <2` +These and other package managers should work if you are bundling your extension. + +### Override Prepublish Script + +This section is optional. By default, `vsce` automatically detects and uses `npm`, `yarn`, `pnpm`, `vlt`, `deno` and `bun` to generate this the `run vscode:prepublish` command. + +- Use `VSCE_RUN_PREPUBLISH="npm run vscode:prepublish"` or `vsce.runPrepublish: "npm run vscode:prepublish"` in your manifest file to override the auto-detected command. +- `vsce.runPrepublish: false` and `VSCE_RUN_PREPUBLISH=0` can disable the prepublish script. This is useful when you already transpiled your extension and you want to compile `.vsix` faster. + ## Configuration You can configure the behavior of `vsce` by using CLI flags (run `vsce --help` to list them all). Example: @@ -52,12 +61,17 @@ Or you can also set them in the `package.json`, so that you avoid having to rety { "vsce": { "baseImagesUrl": "https://my.custom/base/images/url", - "dependencies": true, + "runPrepublish": "pnpm run vscode:prepublish", + "dependencies": false, "yarn": false - } + }, + "packageManager": "pnpm@11.0.0", // optional } ``` +> **Note:** If you are bundling your extension, always set the `dependencies` option to `false`. +In newer version of `vsce` this option is set to `false` automatically, but providing it can make things a bit faster. Same applies to the `yarn` option. + ## Development First clone this repository, then: @@ -79,4 +93,6 @@ Tests can be executed with: $ npm test ``` +Use `VSCE_DEBUG=1` to enable debug output. + > **Note:** [Yarn](https://www.npmjs.com/package/yarn) is required to run the tests. diff --git a/src/api.ts b/src/api.ts index 7a8f419c..2625ab84 100644 --- a/src/api.ts +++ b/src/api.ts @@ -1,5 +1,6 @@ import { publish as _publish, IPublishOptions, unpublish as _unpublish, IUnpublishOptions } from './publish'; -import { packageCommand, listFiles as _listFiles, IPackageOptions } from './package'; +import { packageCommand, listFiles as _listFiles, IPackageOptions, readManifest } from './package'; +import { detectPackageManager } from './npm'; /** * @deprecated prefer IPackageOptions instead @@ -80,12 +81,27 @@ export function publish(options: IPublishOptions = {}): Promise { * Lists the files included in the extension's package. * @public */ -export function listFiles(options: IListFilesOptions = {}): Promise { +export async function listFiles(options: IListFilesOptions = {}): Promise { + const cwd = options.cwd || process.cwd(); + const manifest = await readManifest(cwd); + + let pm: string | null; + switch (options.packageManager) { + case PackageManager.Yarn: pm = 'yarn'; break; + case PackageManager.Npm: pm = 'npm'; break; + case PackageManager.None: pm = null; break; + + case undefined: + default: + // cares all: detect prepublish script launcher + pm = await detectPackageManager(cwd, manifest, false); break; + } + return _listFiles({ ...options, useYarn: options.packageManager === PackageManager.Yarn, dependencies: options.packageManager !== PackageManager.None, - }); + }, pm); } /** diff --git a/src/main.ts b/src/main.ts index 68d14e3a..0cff90bc 100644 --- a/src/main.ts +++ b/src/main.ts @@ -78,7 +78,7 @@ module.exports = function (argv: string[]): void { ) .option('--ignoreFile ', 'Indicate alternative .vscodeignore') // default must remain undefined for dependencies or we will fail to load defaults from package.json - .option('--dependencies', 'Enable dependency detection via npm or yarn', undefined) + .option('--dependencies', 'Enable dependency detection via npm or yarn. Never enable this option if you are bundling your extension', undefined) .option('--no-dependencies', 'Disable dependency detection via npm or yarn', undefined) .option('--readme-path ', 'Path to README file (defaults to README.md)') .option('--follow-symlinks', 'Recurse into symlinked directories instead of treating them as files') @@ -118,7 +118,7 @@ module.exports = function (argv: string[]): void { .option('--no-gitHubIssueLinking', 'Disable automatic expansion of GitHub-style issue syntax into links') .option('--no-gitLabIssueLinking', 'Disable automatic expansion of GitLab-style issue syntax into links') // default must remain undefined for dependencies or we will fail to load defaults from package.json - .option('--dependencies', 'Enable dependency detection via npm or yarn', undefined) + .option('--dependencies', 'Enable dependency detection via npm or yarn. Never enable this option if you are bundling your extension', undefined) .option('--no-dependencies', 'Disable dependency detection via npm or yarn', undefined) .option('--pre-release', 'Mark this package as a pre-release') .option('--allow-star-activation', 'Allow using * in activation events') @@ -244,7 +244,7 @@ module.exports = function (argv: string[]): void { .option('--allow-package-env-file', 'Allow packaging .env files') .option('--ignoreFile ', 'Indicate alternative .vscodeignore') // default must remain undefined for dependencies or we will fail to load defaults from package.json - .option('--dependencies', 'Enable dependency detection via npm or yarn', undefined) + .option('--dependencies', 'Enable dependency detection via npm or yarn. Never enable this option if you are bundling your extension', undefined) .option('--no-dependencies', 'Disable dependency detection via npm or yarn', undefined) .option('--pre-release', 'Mark this package as a pre-release') .option('--allow-star-activation', 'Allow using * in activation events') diff --git a/src/manifest.ts b/src/manifest.ts index cb2d8234..07a4cf39 100644 --- a/src/manifest.ts +++ b/src/manifest.ts @@ -108,6 +108,11 @@ export interface ManifestPackage { private?: boolean; pricing?: string; files?: string[]; + packageManager?: string; + devEngines?: { packageManager?: { + name?: string; version?: string; + onFail: "error" | "warn" | "ignore" + } }; // vsce vsce?: any; diff --git a/src/npm.ts b/src/npm.ts index 6ea6de5d..36eb94de 100644 --- a/src/npm.ts +++ b/src/npm.ts @@ -3,6 +3,7 @@ import * as fs from 'fs'; import * as cp from 'child_process'; import parseSemver from 'parse-semver'; import { CancellationToken, log, nonnull } from './util'; +import type { ManifestPackage } from './manifest'; const exists = (file: string) => fs.promises.stat(file).then( @@ -195,28 +196,83 @@ async function getYarnDependencies(cwd: string, packagedDependencies?: string[]) return [...result]; } -export async function detectYarn(cwd: string): Promise { - for (const name of ['yarn.lock', '.yarnrc', '.yarnrc.yaml', '.pnp.cjs', '.yarn']) { - if (await exists(path.join(cwd, name))) { +/** + * Check if the package manager can be used for unbundled extensions. + */ +export function canNotBeUnbundled(pm: string | null): boolean { + return pm !== 'npm' && pm !== 'yarn1'; +} + +const YARN = [ + { name: 'yarn', files: ['.yarnrc.yaml', '.pnp.cjs', '.yarn/releases'] }, + { name: 'yarn1', files: ['.yarnrc', 'yarn.lock'] }, +] as const + +const MANAGERS = [ + ...YARN, + { name: 'pnpm', files: ['pnpm-lock.yaml', 'pnpm-workspace.yaml', '.pnpmfile.cjs'] }, + { name: 'bun', files: ['bun.lock', 'bunfig.toml', 'bun.lockb'] }, + { name: 'vlt', files: ['vlt-lock.json', '.vltrc'] }, + { name: 'deno', files: ['deno.lock', 'deno.json', 'deno.jsonc'] }, + { name: 'npm', files: ['package.json', 'package-lock.json'] }, +] as const; + +export type ManagerName = (typeof MANAGERS)[number]['name']; + +export async function detectPackageManager(cwd: string, manifest: ManifestPackage, useYarn: boolean | undefined, care?: ManagerName[]): Promise { + const m = useYarn ? YARN : care ? MANAGERS.filter(({name}) => care.includes(name)) : MANAGERS; + for (const { name } of m) { + if ( + manifest?.devEngines?.packageManager?.name === name || + manifest?.packageManager?.startsWith(`${name}@`) + ) { + if (process.env['VSCE_DEBUG']) console.log('Package manager:', name); + return name; + } + } + + for (const mgr of m) { + for (const filename of mgr.files) { + if (!await exists(path.join(cwd, filename))) { + continue; + } if (!process.env['VSCE_TESTS']) { - log.info( - `Detected presence of ${name}. Using 'yarn' instead of 'npm' (to override this pass '--no-yarn' on the command line).` - ); + const suffix = mgr.name === 'yarn' + ? " instead of 'npm' (to override this pass '--no-yarn' on the command line)." + : ' logic.'; + log.info(`Detected presence of ${filename}. Using '${mgr.name}'${suffix}`); } - return true; + if (process.env['VSCE_DEBUG']) console.log('Package manager:', mgr.name); + return mgr.name; } } - return false; + + if (process.env['VSCE_DEBUG']) console.log('Package manager: null'); + return null; +} + +export async function getPrepublishCommand(manifest: ManifestPackage, pm: string | null): Promise { + const envv = process.env['VSCE_RUN_PREPUBLISH'] + if (envv === "" || envv === "0" || manifest?.vsce?.runPrepublish === false) return ""; + const customCommand = envv || manifest?.vsce?.runPrepublish; + if (customCommand) { + return customCommand; + } + + if (pm === null) return 'npm run vscode:prepublish'; + if (pm === 'deno') return 'npm run vscode:prepublish'; + if (pm === 'yarn1') return 'yarn run vscode:prepublish'; + return pm + ' run vscode:prepublish'; // known pms } export async function getDependencies( cwd: string, - dependencies: 'npm' | 'yarn' | 'none' | undefined, + dependencies: 'npm' | 'yarn' | 'none', packagedDependencies?: string[] ): Promise { if (dependencies === 'none') { return [cwd]; - } else if (dependencies === 'yarn' || (dependencies === undefined && (await detectYarn(cwd)))) { + } else if (dependencies === 'yarn') { return await getYarnDependencies(cwd, packagedDependencies); } else { return await getNpmDependencies(cwd); diff --git a/src/package.ts b/src/package.ts index 2aad8818..b11cb165 100644 --- a/src/package.ts +++ b/src/package.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import { promisify } from 'util'; import * as cp from 'child_process'; import * as yazl from 'yazl'; -import { ExtensionKind, ManifestPackage, UnverifiedManifest } from './manifest'; +import type { ExtensionKind, ManifestPackage, UnverifiedManifest } from './manifest'; import { ITranslations, patchNLS } from './nls'; import * as util from './util'; import { glob } from 'glob'; @@ -23,7 +23,12 @@ import { validatePublisher, validateExtensionDependencies, } from './validation'; -import { detectYarn, getDependencies } from './npm'; +import { + detectPackageManager, + getDependencies, + getPrepublishCommand, + canNotBeUnbundled, +} from './npm'; import * as GitHost from 'hosted-git-info'; import parseSemver from 'parse-semver'; import * as jsonc from 'jsonc-parser'; @@ -378,7 +383,7 @@ export interface IVersionBumpOptions { readonly updatePackageJson?: boolean; } -export async function versionBump(options: IVersionBumpOptions): Promise { +export async function versionBump(options: IVersionBumpOptions, pm?: string | null): Promise { if (!options.version) { return; } @@ -389,6 +394,8 @@ export async function versionBump(options: IVersionBumpOptions): Promise { const cwd = options.cwd ?? process.cwd(); const manifest = await readManifest(cwd); + // cares bun: bun pm version + if (pm === undefined) pm = await detectPackageManager(cwd, manifest, undefined, ['npm', 'bun']); if (manifest.version === options.version) { return; @@ -411,9 +418,8 @@ export async function versionBump(options: IVersionBumpOptions): Promise { } } - - // call `npm version` to do our dirty work - const args = ['version', options.version]; + // call `npm version` or `bun pm version` to do our dirty work + const args = pm === 'bun' ? ['pm', 'version', options.version] : ['version', options.version]; const isWindows = process.platform === 'win32'; @@ -426,7 +432,12 @@ export async function versionBump(options: IVersionBumpOptions): Promise { args.push('--no-git-tag-version'); } - const { stdout, stderr } = await promisify(cp.execFile)(isWindows ? 'npm.cmd' : 'npm', args, { cwd, shell: isWindows /* https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 */ }); + const bin = pm === 'bun' ? 'bun' + : isWindows ? 'npm.cmd' : 'npm' + const { stdout, stderr } = await promisify(cp.execFile)(bin, args, { + cwd, + shell: isWindows /* https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2 */ + }); if (!process.env['VSCE_TESTS']) { process.stdout.write(stdout); process.stderr.write(stderr); @@ -1667,103 +1678,112 @@ const defaultIgnore = [ async function collectAllFiles( cwd: string, - dependencies: 'npm' | 'yarn' | 'none' | undefined, + dependencies: 'npm' | 'yarn' | 'none', dependencyEntryPoints?: string[], followSymlinks: boolean = true ): Promise { const deps = await getDependencies(cwd, dependencies, dependencyEntryPoints); const promises = deps.map(dep => - glob('**', { cwd: dep, nodir: true, follow: followSymlinks, dot: true, ignore: 'node_modules/**' }).then(files => + glob('**', { cwd: dep, nodir: true, follow: followSymlinks, dot: true, ignore: ['node_modules/**', ".git/**"] }).then(files => files.map(f => path.relative(cwd, path.join(dep, f))).map(f => f.replace(/\\/g, '/')) ) ); - - return Promise.all(promises).then(util.flatten); + const files = (await Promise.all(promises)).flat(); + return files; } -function getDependenciesOption(options: IPackageOptions): 'npm' | 'yarn' | 'none' | undefined { +async function getDependenciesOption(options: IPackageOptions, pm: string | null): Promise<'npm' | 'yarn' | 'none'> { if (options.dependencies === false) { + if (process.env['VSCE_DEBUG']) console.log('Dep option:', 'none (options.dependencies is false)'); return 'none'; } - switch (options.useYarn) { - case true: - return 'yarn'; - case false: - return 'npm'; - default: - return undefined; - } + const isUnsupported = canNotBeUnbundled(pm); + if (isUnsupported) { + if (options.dependencies) { + util.log.warn("You are trying to include node_modules into your extension, but it should be bundled. Do not use --dependencies.") + } + if (process.env['VSCE_DEBUG']) console.log('Dep option:', 'none (can not be unbundled)'); + return 'none' + }; + + const useYarn = options.useYarn ?? pm === 'yarn1'; + const depOption = useYarn ? 'yarn' : 'npm'; + if (process.env['VSCE_DEBUG']) console.log('Dep option:', depOption); + return depOption; } -function collectFiles( +async function collectFiles( cwd: string, - dependencies: 'npm' | 'yarn' | 'none' | undefined, + manifest: ManifestPackage, + dependencies: 'npm' | 'yarn' | 'none', dependencyEntryPoints?: string[], ignoreFile?: string, - manifestFileIncludes?: string[], readmePath?: string, followSymlinks: boolean = false ): Promise { + const manifestFileIncludes = manifest?.files; readmePath = readmePath ?? 'README.md'; const notIgnored = ['!package.json', `!${readmePath}`]; - return collectAllFiles(cwd, dependencies, dependencyEntryPoints, followSymlinks).then(files => { - files = files.filter(f => !/\r$/m.test(f)); - - return ( - fs.promises - .readFile(ignoreFile ? ignoreFile : path.join(cwd, '.vscodeignore'), 'utf8') - .catch(err => - err.code !== 'ENOENT' ? - Promise.reject(err) : - ignoreFile ? - Promise.reject(err) : - // No .vscodeignore file exists - manifestFileIncludes ? - // include all files in manifestFileIncludes and ignore the rest - Promise.resolve(manifestFileIncludes.map(file => `!${file}`).concat(['**']).join('\n\r')) : - // "files" property not used in package.json - Promise.resolve('') - ) - - // Parse raw ignore by splitting output into lines and filtering out empty lines and comments - .then(rawIgnore => - rawIgnore - .split(/[\n\r]/) - .map(s => s.trim()) - .filter(s => !!s) - .filter(i => !/^\s*#/.test(i)) - ) - - // Add '/**' to possible folder names - .then(ignore => [ - ...ignore, - ...ignore.filter(i => !/(^|\/)[^/]*\*[^/]*$/.test(i)).map(i => (/\/$/.test(i) ? `${i}**` : `${i}/**`)), - ]) - - // Combine with default ignore list - .then(ignore => [...defaultIgnore, ...ignore, ...notIgnored]) - - // Split into ignore and negate list - .then(ignore => - ignore.reduce<[string[], string[]]>( - (r, e) => (!/^\s*!/.test(e) ? [[...r[0], e], r[1]] : [r[0], [...r[1], e]]), - [[], []] - ) - ) - .then(r => ({ ignore: r[0], negate: r[1] })) - - // Filter out files - .then(({ ignore, negate }) => - files.filter( - f => - !ignore.some(i => minimatch(f, i, MinimatchOptions)) || - negate.some(i => minimatch(f, i.substr(1), MinimatchOptions)) - ) - ) - ); - }); + let rawIgnore = ''; + try { + rawIgnore = await fs.promises.readFile(ignoreFile ? ignoreFile : path.join(cwd, '.vscodeignore'), 'utf8'); + } catch (err) { + if ((err as NodeJS.ErrnoException)?.code !== 'ENOENT') throw err; + if (ignoreFile) throw err; // No .vscodeignore file exists + // include all files in manifestFileIncludes and ignore the rest + if(manifestFileIncludes) { + rawIgnore = manifestFileIncludes + .map(file => `!${file}`) + .concat(['**']) + .join('\n\r') + } + // otherwise "files" property not used in package.json + } + + // Parse raw ignore by splitting output into lines and filtering out empty lines and comments + let i = rawIgnore + .split(/[\n\r]/) + .map(s => s.trim()) + .filter(s => !!s) + .filter(i => !/^\s*#/.test(i)) + + // Add '/**' to possible folder names + // Combine with default ignore list + i = [ + ...defaultIgnore, + ...i, + ...i.filter(i => !/(^|\/)[^/]*\*[^/]*$/.test(i)).map(i => (/\/$/.test(i) ? `${i}**` : `${i}/**`)), + ...notIgnored, + ] + + const anyNM = [ + "node_modules/**", + "node_modules", + "**/node_modules/**", + + "**/node_modules", + "/node_modules", + "/node_modules/**", + ] + const isNMCompletelyIgnored = anyNM.some(p => i.some(j => j === p)); + if (process.env['VSCE_DEBUG'] && isNMCompletelyIgnored) console.log("node_modules are completely ignored."); + + // Split into ignore and negate list + const [ignore, negate] = i.reduce<[string[], string[]]>( + (r, e) => (!/^\s*!/.test(e) ? [[...r[0], e], r[1]] : [r[0], [...r[1], e.substring(1)]]), + [[], []] + ) + + const files = (await collectAllFiles(cwd, isNMCompletelyIgnored ? "none" : dependencies, dependencyEntryPoints, followSymlinks)) + .filter(f => !/\r$/m.test(f)); + + return files.filter( + f => + !ignore.some(i => minimatch(f, i, MinimatchOptions)) || + negate.some(i => minimatch(f, i, MinimatchOptions)) + ); } export function processFiles(processors: IProcessor[], files: IFile[]): Promise { @@ -1809,13 +1829,16 @@ export function createDefaultProcessors(manifest: ManifestPackage, options: IPac ]; } -export function collect(manifest: ManifestPackage, options: IPackageOptions = {}): Promise { +export async function collect(manifest: ManifestPackage, options: IPackageOptions = {}, pm?: string | null): Promise { const cwd = options.cwd || process.cwd(); const packagedDependencies = options.dependencyEntryPoints || undefined; const ignoreFile = options.ignoreFile || undefined; const processors = createDefaultProcessors(manifest, options); - return collectFiles(cwd, getDependenciesOption(options), packagedDependencies, ignoreFile, manifest.files, options.readmePath, options.followSymlinks).then(fileNames => { + // cares yarn: only yarn and npm deps are supported + if (pm === undefined) pm = await detectPackageManager(cwd, manifest, options.useYarn, ['npm', 'yarn1']); + + return collectFiles(cwd, manifest, await getDependenciesOption(options, pm), packagedDependencies, ignoreFile, options.readmePath, options.followSymlinks).then(fileNames => { const files = fileNames.map(f => ({ path: util.filePathToVsixPath(f), localPath: path.join(cwd, f) })); return processFiles(processors, files); @@ -1871,24 +1894,21 @@ function getDefaultPackageName(manifest: ManifestPackage, options: IPackageOptio return `${manifest.name}-${version}.vsix`; } -export async function prepublish(cwd: string, manifest: ManifestPackage, useYarn?: boolean): Promise { +export async function prepublish(cwd: string, manifest: ManifestPackage, pm: string | null): Promise { if (!manifest.scripts || !manifest.scripts['vscode:prepublish']) { return; } - if (useYarn === undefined) { - useYarn = await detectYarn(cwd); - } + const prepublish = await getPrepublishCommand(manifest, pm); - const tool = useYarn ? 'yarn' : 'npm'; - const prepublish = `${tool} run vscode:prepublish`; + if (!prepublish) return; console.log(`Executing prepublish script '${prepublish}'...`); await new Promise((c, e) => { // Use string command to avoid Node.js DEP0190 warning (args + shell: true is deprecated). const child = cp.spawn(prepublish, { cwd, shell: true, stdio: 'inherit' }); - child.on('exit', code => (code === 0 ? c() : e(`${tool} failed with exit code ${code}`))); + child.on('exit', code => (code === 0 ? c() : e(`'${prepublish}' failed with exit code ${code}`))); child.on('error', e); }); } @@ -1911,10 +1931,13 @@ async function getPackagePath(cwd: string, manifest: ManifestPackage, options: I } } -export async function pack(options: IPackageOptions = {}): Promise { +export async function pack(options: IPackageOptions = {}, pm?: string | null): Promise { const cwd = options.cwd || process.cwd(); const manifest = await readManifest(cwd); - const files = await collect(manifest, options); + + // cares yarn: only yarn and npm deps are supported + if (pm === undefined) pm = await detectPackageManager(cwd, manifest, options.useYarn, ['npm', 'yarn1']); + const files = await collect(manifest, options, pm); await printAndValidatePackagedFiles(files, cwd, manifest, options); @@ -1986,10 +2009,12 @@ export async function packageCommand(options: IPackageOptions = {}): Promise { +export async function listFiles(options: IListFilesOptions = {}, pm: string | null): Promise { const cwd = options.cwd ?? process.cwd(); const manifest = options.manifest ?? await readManifest(cwd); if (options.prepublish) { - await prepublish(cwd, manifest, options.useYarn); + // cares all: detect prepublish script launcher + await prepublish(cwd, manifest, pm); } - return await collectFiles(cwd, getDependenciesOption(options), options.packagedDependencies, options.ignoreFile, manifest.files, options.readmePath, options.followSymlinks); + // cares yarn + return await collectFiles(cwd, manifest, await getDependenciesOption(options, pm), options.packagedDependencies, options.ignoreFile, options.readmePath, options.followSymlinks); } interface ILSOptions { @@ -2043,7 +2070,10 @@ export async function ls(options: ILSOptions = {}): Promise { const cwd = process.cwd(); const manifest = await readManifest(cwd); - const files = await listFiles({ ...options, cwd, manifest }); + // cares all: detect prepublish script launcher + const pm = await detectPackageManager(cwd, manifest, options.useYarn); + + const files = await listFiles({ ...options, cwd, manifest }, pm); if (options.tree) { const printableFileStructure = await util.generateFileStructureTree( diff --git a/src/publish.ts b/src/publish.ts index 7475afcb..0b3e3abf 100644 --- a/src/publish.ts +++ b/src/publish.ts @@ -14,6 +14,7 @@ import FormData from 'form-data'; import { basename } from 'path'; import { IterableBackoff, handleWhen, retry } from 'cockatiel'; import { getAzureCredentialAccessToken } from './auth'; +import { detectPackageManager } from './npm'; const tmpName = promisify(tmp.tmpName); @@ -159,20 +160,23 @@ export async function publish(options: IPublishOptions = {}): Promise { // Validate marketplace requirements before prepublish to avoid unnecessary work validateManifestForPublishing(manifest, options); - await prepublish(cwd, manifest, options.useYarn); - await versionBump(options); + // cares all: detect prepublish script launcher + const pm = await detectPackageManager(cwd, manifest, options.useYarn); + + await prepublish(cwd, manifest, pm); + await versionBump(options, pm); if (options.targets) { for (const target of options.targets) { const packagePath = await tmpName(); - const packageResult = await pack({ ...options, target, packagePath }); + const packageResult = await pack({ ...options, target, packagePath }, pm); const manifestValidated = validateManifestForPublishing(packageResult.manifest, options); const sigzipPath = options.signTool ? await signPackage(packagePath, options.signTool) : undefined; await _publish(packagePath, sigzipPath, manifestValidated, { ...options, target }); } } else { const packagePath = await tmpName(); - const packageResult = await pack({ ...options, packagePath }); + const packageResult = await pack({ ...options, packagePath }, pm); const manifestValidated = validateManifestForPublishing(packageResult.manifest, options); const sigzipPath = options.signTool ? await signPackage(packagePath, options.signTool) : undefined; await _publish(packagePath, sigzipPath, manifestValidated, options);