Skip to content

Commit

Permalink
feat: release a pure esm package
Browse files Browse the repository at this point in the history
BREAKING CHANGE:

this package is pure esm now, which means you need to use `import` statement to load it, [faq](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)
  • Loading branch information
egoist committed Jan 26, 2022
1 parent 3eeec3c commit 41fa185
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 75 deletions.
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
{
"name": "bundle-require",
"version": "0.0.0",
"version": "0.0.0-semantic-release",
"description": "bundle and require a file",
"publishConfig": {
"access": "public"
},
"files": [
"dist"
],
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsup src/index.ts --format cjs --dts-resolve --target node16",
"build": "tsup src/index.ts --format esm --dts-resolve --target node16",
"test": "npm run build && vitest run",
"prepublishOnly": "npm run build"
},
Expand All @@ -20,13 +21,14 @@
"@egoist/prettier-config": "^1.0.0",
"@types/node": "^16.11.7",
"esbuild": "^0.13.13",
"load-tsconfig": "^0.1.2",
"prettier": "^2.5.1",
"strip-json-comments": "^4.0.0",
"tsup": "^5.11.11",
"typescript": "^4.5.5",
"vitest": "^0.2.3"
},
"dependencies": {
"load-tsconfig": "^0.2.0"
},
"peerDependencies": {
"esbuild": ">=0.13"
}
Expand Down
17 changes: 9 additions & 8 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 22 additions & 22 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import fs from 'fs'
import path from 'path'
import { pathToFileURL } from 'url'
import fs from "fs"
import path from "path"
import { pathToFileURL } from "url"
import {
build,
Loader,
BuildOptions,
BuildFailure,
BuildResult,
Plugin as EsbuildPlugin,
} from 'esbuild'
import { loadTsConfig } from 'load-tsconfig'
import { dynamicImport, guessFormat, jsoncParse } from './utils'
} from "esbuild"
import { loadTsConfig } from "load-tsconfig"
import { dynamicImport, guessFormat } from "./utils"

export const JS_EXT_RE = /\.(mjs|cjs|ts|js|tsx|jsx)$/

function inferLoader(ext: string): Loader {
if (ext === '.mjs' || ext === '.cjs') return 'js'
if (ext === ".mjs" || ext === ".cjs") return "js"
return ext.slice(1) as Loader
}

export { dynamicImport, jsoncParse }
export { dynamicImport }

export type RequireFunction = (
outfile: string,
ctx: { format: 'cjs' | 'esm' },
ctx: { format: "cjs" | "esm" },
) => any

export type GetOutputFile = (filepath: string, format: 'esm' | 'cjs') => string
export type GetOutputFile = (filepath: string, format: "esm" | "cjs") => string

export interface Options {
cwd?: string
Expand Down Expand Up @@ -75,14 +75,14 @@ export interface Options {
const defaultGetOutputFile: GetOutputFile = (filepath, format) =>
filepath.replace(
JS_EXT_RE,
`.bundled_${Date.now()}.${format === 'esm' ? 'mjs' : 'cjs'}`,
`.bundled_${Date.now()}.${format === "esm" ? "mjs" : "cjs"}`,
)

export { loadTsConfig }

export const tsconfigPathsToRegExp = (paths: Record<string, any>) => {
return Object.keys(paths || {}).map((key) => {
return new RegExp(`^${key.replace(/\*/, '.*')}$`)
return new RegExp(`^${key.replace(/\*/, ".*")}$`)
})
}

Expand All @@ -92,7 +92,7 @@ export const match = (id: string, patterns?: (string | RegExp)[]) => {
if (p instanceof RegExp) {
return p.test(id)
}
return id === p || id.startsWith(p + '/')
return id === p || id.startsWith(p + "/")
})
}

Expand All @@ -107,10 +107,10 @@ export const externalPlugin = ({
notExternal?: (string | RegExp)[]
} = {}): EsbuildPlugin => {
return {
name: 'bundle-require:external',
name: "bundle-require:external",
setup(ctx) {
ctx.onResolve({ filter: /.*/ }, async (args) => {
if (args.path[0] === '.' || path.isAbsolute(args.path)) {
if (args.path[0] === "." || path.isAbsolute(args.path)) {
// Fallback to default
return
}
Expand All @@ -137,10 +137,10 @@ export const externalPlugin = ({

export const replaceDirnamePlugin = (): EsbuildPlugin => {
return {
name: 'bundle-require:replace-path',
name: "bundle-require:replace-path",
setup(ctx) {
ctx.onLoad({ filter: JS_EXT_RE }, async (args) => {
const contents = await fs.promises.readFile(args.path, 'utf-8')
const contents = await fs.promises.readFile(args.path, "utf-8")
return {
contents: contents
.replace(/\b__filename\b/g, JSON.stringify(args.path))
Expand Down Expand Up @@ -180,13 +180,13 @@ export async function bundleRequire(options: Options) {
const getOutputFile = options.getOutputFile || defaultGetOutputFile
const outfile = getOutputFile(options.filepath, format)

await fs.promises.writeFile(outfile, text, 'utf8')
await fs.promises.writeFile(outfile, text, "utf8")

let mod: any
const req: RequireFunction = options.require || dynamicImport
try {
mod = await req(
format === 'esm' ? pathToFileURL(outfile).href : outfile,
format === "esm" ? pathToFileURL(outfile).href : outfile,
{ format },
)
} finally {
Expand All @@ -206,10 +206,10 @@ export async function bundleRequire(options: Options) {
...options.esbuildOptions,
entryPoints: [options.filepath],
absWorkingDir: cwd,
outfile: 'out.js',
outfile: "out.js",
format,
platform: 'node',
sourcemap: 'inline',
platform: "node",
sourcemap: "inline",
bundle: true,
metafile: true,
write: false,
Expand Down
45 changes: 19 additions & 26 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,36 @@
import fs from 'fs'
import path from 'path'
import strip from 'strip-json-comments'
import { RequireFunction } from '.'

export function jsoncParse(data: string) {
try {
return new Function('return ' + strip(data).trim())()
} catch (_) {
// Silently ignore any error
// That's what tsc/jsonc-parser did after all
return {}
}
}
import fs from "fs"
import path from "path"
import { createRequire } from "module"
import { RequireFunction } from "."

const getPkgType = (): string | undefined => {
try {
const pkg = JSON.parse(
fs.readFileSync(path.resolve('package.json'), 'utf-8'),
fs.readFileSync(path.resolve("package.json"), "utf-8"),
)
return pkg.type
} catch (error) {}
}

export function guessFormat(inputFile: string): 'esm' | 'cjs' {
if (!usingDynamicImport) return 'cjs'
export function guessFormat(inputFile: string): "esm" | "cjs" {
if (!usingDynamicImport) return "cjs"

const ext = path.extname(inputFile)
const type = getPkgType()
if (ext === '.js') {
return type === 'module' ? 'esm' : 'cjs'
} else if (ext === '.ts') {
return 'esm'
} else if (ext === '.mjs') {
return 'esm'
if (ext === ".js") {
return type === "module" ? "esm" : "cjs"
} else if (ext === ".ts") {
return "esm"
} else if (ext === ".mjs") {
return "esm"
}
return 'cjs'
return "cjs"
}

declare const jest: any

// Stolen from https://github.com/vitejs/vite/blob/0713446fa4df678422c84bd141b189a930c100e7/packages/vite/src/node/utils.ts#L606
export const usingDynamicImport = typeof jest === 'undefined'
export const usingDynamicImport = typeof jest === "undefined"
/**
* Dynamically import files.
*
Expand All @@ -54,6 +44,9 @@ export const dynamicImport: RequireFunction = async (
id: string,
{ format },
) => {
const fn = format === 'esm' ? (file: string) => import(file) : require
const fn =
format === "esm"
? (file: string) => import(file)
: createRequire(import.meta.url)
return fn(id)
}
16 changes: 1 addition & 15 deletions test/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test, assert } from "vitest"
import fs from "fs"
import path from "path"
import { bundleRequire, jsoncParse, JS_EXT_RE } from "../dist"
import { bundleRequire, JS_EXT_RE } from "../dist"

test("main", async () => {
const { mod, dependencies } = await bundleRequire({
Expand Down Expand Up @@ -46,17 +46,3 @@ test("resolve tsconfig paths", async () => {
})
assert.equal(mod.foo, "foo")
})

test("jsonc parse", () => {
assert.deepEqual(
jsoncParse(`
// some comment
{
"foo": "bar" // good
/* another comment */
}
`),
{ foo: "bar" },
)
})

0 comments on commit 41fa185

Please sign in to comment.