Skip to content

Commit

Permalink
feat: cache support
Browse files Browse the repository at this point in the history
  • Loading branch information
pooya parsa committed Jun 11, 2020
1 parent 7c45e86 commit 65c2de2
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 10 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- Super slim and zero dependency
- Syntax detect to avoid extra transform
- CommonJS cache integration
- Filesystem transpile cache + V8 compile cache

## Usage

Expand All @@ -29,7 +30,7 @@ jiti('./path/to/file.ts')
- `+` Much more stable thanks to babel
- `+` Less low level operations
- `+` Typescript support
- `-` Slower
- `-` Slower (without cache)

### [`babel-register`](https://babeljs.io/docs/en/babel-register)

Expand Down Expand Up @@ -77,7 +78,7 @@ Meanwhile it would be much better making an optimized bundle to deploy to produc
- [x] Basic working
- [x] Syntax detect and fallback to CJS require
- [x] Improve project build system
- [ ] File system cache
- [x] File system cache
- [ ] Add tests
- [ ] Configurable transform (esbuild)

Expand Down
4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,19 @@
"@babel/preset-typescript": "^7.10.1",
"@nuxtjs/eslint-config-typescript": "^2.0.0",
"@types/babel__core": "^7.1.8",
"@types/mkdirp": "^1.0.1",
"@types/node": "^14.0.11",
"@types/resolve": "^1.17.1",
"create-require": "^1.0.1",
"eslint": "^7.2.0",
"esm": "^3.2.25",
"mkdirp": "^1.0.4",
"resolve": "^1.17.0",
"standard-version": "^8.0.0",
"ts-loader": "^7.0.5",
"tslib": "^2.0.0",
"typescript": "^3.9.5",
"v8-compile-cache": "^2.1.1",
"webpack": "^5.0.0-beta.17",
"webpack-cli": "^3.3.11"
}
Expand Down
71 changes: 64 additions & 7 deletions src/jiti.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,42 @@
import { readFileSync } from 'fs'
import 'v8-compile-cache'
import { existsSync, readFileSync, writeFileSync } from 'fs'
import { Module, builtinModules } from 'module'
import { dirname } from 'path'
import { dirname, join, basename } from 'path'
import { tmpdir } from 'os'
import { createHash } from 'crypto'
import mkdirp from 'mkdirp'
import createRequire from 'create-require'
// @ts-ignore
import resolve from 'resolve'
import { TransformOptions } from './types'

export type JITIOptions = {
transform: (opts: TransformOptions) => string,
debug: boolean
transform?: (opts: TransformOptions) => string,
debug?: boolean,
cache?: boolean,
cacheDir?: string
}

const defaults = {
debug: false,
cache: true
}

function md5 (content: string, len = 8) {
return createHash('md5').update(content).digest('hex').substr(0, len)
}

export default function createJITI (_filename: string = process.cwd(), opts: JITIOptions): NodeRequire {
opts = { ...defaults, ...opts }

if (opts.cache && !opts.cacheDir) {
const nodeModulesDir = join(process.cwd(), 'node_modules')
if (existsSync(nodeModulesDir)) {
opts.cacheDir = join(nodeModulesDir, '.cache/jiti')
} else {
opts.cacheDir = join(tmpdir(), 'node-jiti')
}
}

// https://www.npmjs.com/package/resolve
const resolveOpts = {
extensions: ['.js', '.mjs', '.ts'],
Expand All @@ -29,6 +54,36 @@ export default function createJITI (_filename: string = process.cwd(), opts: JIT
}
}

function getCache (filename: string, source: string, get: () => string): string {
if (!opts.cache) {
return get()
}

// Calculate source hash
const sourceHash = ` /* ${md5(source, 16)} */`

// Check cache file
let filebase = basename(filename)
if (filename.startsWith('index')) {
filebase = dirname(filename) + '.' + filebase
}
const cacheFile = join(opts.cacheDir!, filebase + '.' + md5(filename) + '.js')

if (existsSync(cacheFile)) {
const cacheSource = readFileSync(cacheFile, 'utf-8')
if (cacheSource.endsWith(sourceHash)) {
return cacheSource
}
}

const result = get()

mkdirp.sync(opts.cacheDir!)
writeFileSync(cacheFile, result + sourceHash, 'utf-8')

return result
}

function jiti (id: string) {
// Check for builtin node module like fs
if (builtinModules.includes(id)) {
Expand All @@ -45,12 +100,14 @@ export default function createJITI (_filename: string = process.cwd(), opts: JIT

// Read source
let source = readFileSync(filename, 'utf-8')

// Transpile if needed
if (filename.match(/\.ts$/)) {
debug('[ts]', filename)
source = opts.transform({ source, filename, ts: true })
source = getCache(filename, source, () => opts.transform!({ source, filename, ts: true }))
} else if (source.match(/^\s*import .* from/m) || source.match(/^\s*export /m)) {
debug('[esm]', filename)
source = opts.transform({ source, filename })
source = getCache(filename, source, () => opts.transform!({ source, filename }))
} else {
debug('[bail]', filename)
return _require(id)
Expand Down
21 changes: 20 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,18 @@
resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=

"@types/mkdirp@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-1.0.1.tgz#0930b948914a78587de35458b86c907b6e98bbf6"
integrity sha512-HkGSK7CGAXncr8Qn/0VqNtExEE+PHMWb+qlR1faHMao7ng6P3tAaoWWBMdva0gL5h4zprjIO89GJOLXsMcDm1Q==
dependencies:
"@types/node" "*"

"@types/node@*":
version "14.0.13"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.13.tgz#ee1128e881b874c371374c1f72201893616417c9"
integrity sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==

"@types/node@^14.0.11":
version "14.0.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.11.tgz#61d4886e2424da73b7b25547f59fdcb534c165a3"
Expand All @@ -326,6 +338,13 @@
resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==

"@types/resolve@^1.17.1":
version "1.17.1"
resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"
integrity sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==
dependencies:
"@types/node" "*"

"@typescript-eslint/eslint-plugin@^2.32.0":
version "2.34.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
Expand Down Expand Up @@ -4426,7 +4445,7 @@ v8-compile-cache@2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==

v8-compile-cache@^2.0.3:
v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
Expand Down

0 comments on commit 65c2de2

Please sign in to comment.