Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix npm package #973

Merged
merged 4 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
deploy:
name: Deploy esm.sh to production
runs-on: ubuntu-latest
environment: release
environment: production

steps:
- name: Checkout
Expand Down Expand Up @@ -111,7 +111,7 @@ jobs:
node-version: 20

- name: Build CLI
run: go build -ldflags="-s -w -X 'github.com/esm-dev/esm.sh/server.VERSION=${github.ref_name}'" -o cli/bin/esm.sh${{ matrix.ext }} esmd cli/cmd/main.go
run: go build -ldflags="-s -w -X 'github.com/esm-dev/esm.sh/server.VERSION=${github.ref_name}'" -o cli/tmp/bin/esm.sh${{ matrix.ext }} cli/cmd/main.go
env:
GOOS: ${{ matrix.os }}
GOARCH: ${{ matrix.arch }}
Expand All @@ -121,16 +121,16 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: esm.sh-cli-${{ matrix.os }}-${{ matrix.arch }}
path: cli/bin/esm.sh${{ matrix.ext }}
path: cli/tmp/bin/esm.sh${{ matrix.ext }}
if-no-files-found: error

- name: Create package.json
run: echo "const p=JSON.parse(require('fs').readFileSync('npm/package.json','utf8'));console.log(JSON.stringify({...p,name:'@esm.sh/cli-${{ matrix.os }}-${{ matrix.arch }}',version:'0.'+('${{ github.ref_name }}'.slice(1))+'.0',os:['${{ matrix.os }}'],cpu:['${{ matrix.arch }}'.replace('amd','x')],files:['bin/'],bin:void 0,scripts:void 0,optionalDependencies:void 0}))" | node > package.json
working-directory: cli
run: echo "const[minor,patch='0']='${{ github.ref_name }}'.slice(1).split('_');const p=JSON.parse(require('fs').readFileSync('../npm/package.json','utf8'));console.log(JSON.stringify({...p,name:'@esm.sh/cli-${{ matrix.os }}-${{ matrix.arch }}',version:['0',minor,patch].join('.'),os:['${{ matrix.os }}'],cpu:['${{ matrix.arch }}'.replace('amd','x')],bin:void 0,scripts:void 0,optionalDependencies:void 0}))" | node > package.json
working-directory: cli/tmp

- name: Publish Package
- name: Publish Package to NPM
run: npm publish --provenance --access public
working-directory: cli
working-directory: cli/tmp
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Expand All @@ -154,7 +154,7 @@ jobs:
node-version: 20

- name: Update Version
run: echo "const fs=require('fs');fs.writeFileSync('package.json',fs.readFileSync('package.json','utf8').replaceAll('*','${{ github.ref_name }}'.slice(1)),'utf8')" | node
run: echo "const fs=require('fs');const[minor,patch='0']='${{ github.ref_name }}'.slice(1).split('_');fs.writeFileSync('package.json',fs.readFileSync('package.json','utf8').replaceAll('*',['0',minor,patch].join('.'),'utf8')" | node
working-directory: cli/npm

- name: Publish Package
Expand Down
73 changes: 73 additions & 0 deletions cli/npm/bin/esm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#!/usr/bin/env node

const { execFileSync } = require("child_process");
const { createWriteStream, existsSync, readFileSync } = require("fs");
const { Writable } = require("stream");
const { join } = require("path");

// On macOS/Linux, this file will be linked to "@esm.sh/cli-{os}-{arch}/bin/esm.sh" by the install script.
// On Windows, or if the install script is interrupted, the binary path is resolved manually and executed.
try {
execFileSync(resolveBinaryPath(), process.argv.slice(2), { stdio: 'inherit' })
} catch (err) {
downloadBinaryFromGitHub().then((res) => {
const binPath = join(__dirname, "esm.sh" + (getBinExtension() || ".bin"));
res.pipeTo.pipeTo(Writable.toWeb(createWriteStream(binPath))).then(() => {
execFileSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
});
});
}

function resolveBinaryPath() {
const exeBinPath = join(__dirname, "esm.sh.exe");
if (existsSync(exeBinPath)) {
return exeBinPath;
}
const cliBinPackage = `@esm.sh/cli-${getOS()}-${getArch()}`;
const binPath = require.resolve(cliBinPackage + "/bin/esm.sh" + getBinExtension());
if (!existsSync(binPath)) {
throw new Error(`Could not find the binary of '${cliBinPackage}'`);
}
return binPath;
}

async function downloadBinaryFromGitHub() {
const pkgInfo = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf8"));
const [_, minor, patch] = pkgInfo.version.split(".");
const tag = "v" + minor + (Number(patch) > 0 ? "_" + patch : "");
const url = `https://github.com/esm-dev/esm.sh/releases/download/${tag}/esm.sh-cli-${getOS()}-${getArch()}.gz`;
const res = await fetch(url);
if (!res.ok) {
res.body?.cancel();
throw new Error(`Download ${url}: <${res.statusText}>`);
}
return res.body.pipeThrough(new DecompressionStream("gzip"));
}

function getOS() {
switch (process.platform) {
case "darwin":
return "darwin";
case "linux":
return "linux";
case "win32":
return "windows";
default:
throw new Error(`Unsupported platform: ${process.platform}`);
}
}

function getArch() {
switch (process.arch) {
case "arm64":
return "arm64";
case "x64":
return "amd64";
default:
throw new Error(`Unsupported architecture: ${process.arch}`);
}
}

function getBinExtension() {
return process.platform === "win32" ? ".exe" : "";
}
80 changes: 38 additions & 42 deletions cli/npm/install.mjs
Original file line number Diff line number Diff line change
@@ -1,91 +1,87 @@
import { chmodSync, cpSync, createWriteStream, existsSync, linkSync, mkdirSync, readFileSync, rmSync, statSync } from "node:fs";
import { chmodSync, cpSync, createWriteStream, existsSync, linkSync, readFileSync, statSync, unlinkSync } from "node:fs";
import { createRequire } from "node:module";
import { arch, platform } from "node:os";
import { Writable } from "node:stream";

// 1. Attempt to resolve "@esm.sh/cli-{os}-{arch}", if not found, then try to download the binary from GitHub.
// 2. On macOS/Linux, link "bin/esm.sh" to "@esm.sh/cli-{os}-{arch}/bin/esm.sh" if exists.
install();

async function install() {
const binPath = toPackagePath("bin/esm.sh" + getBinExtension());
if (!existsSync(binPath)) {
try {
// ensure bin directory exists
mkdirSync(toPackagePath("bin"));
} catch {}
try {
const nativeBinPath = resolveBinaryPath();
if (process.platform !== "win32") {
unlinkSync(binPath);
linkSync(nativeBinPath, binPath);
chmodAddX(binPath);
}
} catch {
try {
if (platform() !== "win32") {
linkSync(await resolveBinaryPath(), binPath);
// chmod +x
chmodSync(binPath, statSync(binPath).mode | 0o111);
} else {
cpSync(await resolveBinaryPath(), binPath);
}
} catch {
try {
const fileStream = createWriteStream(binPath);
console.log("Downloading esm.sh CLI binary from GitHub...");
await downloadBinaryFromGitHub(fileStream);
} catch (err) {
console.error("Failed to install esm.sh CLI binary:", err);
rmSync(toPackagePath("bin"), { recursive: true });
process.exit(1);
}
console.log("[esm.sh] Trying to download esm.sh binary from GitHub...");
const readable = await downloadBinaryFromGitHub();
await readable.pipeTo(Writable.toWeb(createWriteStream(binPath)));
chmodAddX(binPath);
} catch (err) {
console.error("[esm.sh] Failed to install esm.sh binary:", err);
throw err;
}
}
}

async function resolveBinaryPath() {
const cliBinPackage = `@esm.sh/cli-${getPlatform()}-${getArch()}`;
function resolveBinaryPath() {
const cliBinPackage = `@esm.sh/cli-${getOS()}-${getArch()}`;
const binPath = createRequire(import.meta.url).resolve(cliBinPackage + "/bin/esm.sh" + getBinExtension());
if (!existsSync(binPath)) {
throw new Error(`Package '${cliBinPackage}' may be installed incorrectly`);
throw new Error(`Could not find the binary of '${cliBinPackage}'`);
}
return binPath;
}

async function downloadBinaryFromGitHub(w) {
async function downloadBinaryFromGitHub() {
const pkgInfo = JSON.parse(readFileSync(toPackagePath("package.json"), "utf8"));
const version = pkgInfo.version.split(".")[1];
const url = `https://github.com/esm-dev/esm.sh/releases/download/v${version}/esm.sh-cli-${getPlatform()}-${getArch()}.gz`;
const [_, minor, patch] = pkgInfo.version.split(".");
const tag = "v" + minor + (Number(patch) > 0 ? "_" + patch : "");
const url = `https://github.com/esm-dev/esm.sh/releases/download/${tag}/esm.sh-cli-${getOS()}-${getArch()}.gz`;
const res = await fetch(url);
if (!res.ok) {
res.body?.cancel?.();
res.body?.cancel();
throw new Error(`Download ${url}: <${res.statusText}>`);
}
await res.body.pipeThrough(new DecompressionStream("gzip")).pipeTo(Writable.toWeb(w));
return res.body.pipeThrough(new DecompressionStream("gzip"));
}

function getPlatform() {
let os = platform();
os = os === "win32" ? "windows" : os;
switch (os) {
function getOS() {
switch (process.platform) {
case "darwin":
return "darwin";
case "linux":
return "linux";
case "win32":
return "windows";
default:
throw new Error(`Unsupported platform: ${os}`);
throw new Error(`Unsupported platform: ${process.platform}`);
}
}

function getArch() {
const a = arch();
switch (a) {
switch (process.arch) {
case "arm64":
return "arm64";
case "x64":
return "amd64";
default:
throw new Error(`Unsupported architecture: ${a}`);
throw new Error(`Unsupported architecture: ${process.arch}`);
}
}

function getBinExtension() {
return platform() === "win32" ? ".exe" : "";
return process.platform === "win32" ? ".exe" : "";
}

function toPackagePath(filename) {
return new URL(filename, import.meta.url).pathname;
}

install();
function chmodAddX(path) {
chmodSync(path, statSync(path).mode | 0o111);
}
12 changes: 6 additions & 6 deletions cli/npm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "esm.sh",
"version": "0.*.0",
"version": "*",
"description": "A no-build CDN for modern web development.",
"repository": {
"type": "git",
Expand All @@ -14,11 +14,11 @@
"postinstall": "node install.mjs"
},
"optionalDependencies": {
"@esm.sh/cli-darwin-arm64": "0.*.0",
"@esm.sh/cli-darwin-amd64": "0.*.0",
"@esm.sh/cli-linux-arm64": "0.*.0",
"@esm.sh/cli-linux-amd64": "0.*.0",
"@esm.sh/cli-windows-amd64": "0.*.0"
"@esm.sh/cli-darwin-arm64": "*",
"@esm.sh/cli-darwin-amd64": "*",
"@esm.sh/cli-linux-arm64": "*",
"@esm.sh/cli-linux-amd64": "*",
"@esm.sh/cli-windows-amd64": "*"
},
"engines": {
"node": ">=18"
Expand Down
Loading