Skip to content

Commit dd854d5

Browse files
ayuhitofarnabaz
andauthored
perf(git): use modern-tar over tar (#3569)
Co-authored-by: Farnabaz <[email protected]>
1 parent e166063 commit dd854d5

File tree

8 files changed

+104
-18
lines changed

8 files changed

+104
-18
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
"micromatch": "^4.0.8",
8787
"minimark": "^0.2.0",
8888
"minimatch": "^10.0.3",
89+
"modern-tar": "^0.6.1",
8990
"nuxt-component-meta": "https://pkg.pr.new/nuxt-component-meta@e3eb2c4",
9091
"nypm": "^0.6.2",
9192
"ohash": "^2.0.11",
@@ -97,7 +98,6 @@
9798
"slugify": "^1.6.6",
9899
"socket.io-client": "^4.8.1",
99100
"std-env": "^3.10.0",
100-
"tar": "^7.5.1",
101101
"tinyglobby": "^0.2.15",
102102
"ufo": "^1.6.1",
103103
"unctx": "^2.4.1",

pnpm-lock.yaml

Lines changed: 9 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/utils/git.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { createWriteStream } from 'node:fs'
1+
import { createReadStream, createWriteStream } from 'node:fs'
22
import { mkdir, readFile, rm, writeFile } from 'node:fs/promises'
3-
import { pipeline } from 'node:stream'
4-
import { promisify } from 'node:util'
3+
import { pipeline } from 'node:stream/promises'
4+
import { createGunzip } from 'node:zlib'
55
import { join } from 'pathe'
6-
import { extract } from 'tar'
76
import { readGitConfig } from 'pkg-types'
87
import gitUrlParse from 'git-url-parse'
8+
import { unpackTar } from 'modern-tar/fs'
99

1010
export interface GitInfo {
1111
// Repository name
@@ -39,16 +39,15 @@ export async function downloadRepository(url: string, cwd: string, { headers }:
3939
try {
4040
const response = await fetch(url, { headers })
4141
const stream = createWriteStream(tarFile)
42-
await promisify(pipeline)(response.body as unknown as ReadableStream[], stream)
43-
44-
await extract({
45-
file: tarFile,
46-
cwd: cwd,
47-
onentry(entry) {
48-
// Remove root directory from zip contents to save files directly in cwd
49-
entry.path = entry.path.split('/').splice(1).join('/')
50-
},
51-
})
42+
await pipeline(response.body as unknown as ReadableStream[], stream)
43+
44+
await pipeline(
45+
createReadStream(tarFile),
46+
createGunzip(),
47+
unpackTar(cwd, {
48+
strip: 1, // Remove root directory from zip contents to save files directly in cwd
49+
}),
50+
)
5251

5352
await writeFile(cacheFile, JSON.stringify({
5453
url: url,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<template>
2+
<div>
3+
<NuxtRouteAnnouncer />
4+
<NuxtWelcome />
5+
</div>
6+
</template>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { defineCollection, defineContentConfig } from '@nuxt/content'
2+
3+
export default defineContentConfig({
4+
collections: {
5+
content: defineCollection({
6+
type: 'page',
7+
source: {
8+
repository: 'https://github.com/nuxt/content',
9+
include: 'docs/content/**',
10+
exclude: [
11+
'**/_dir.yml',
12+
],
13+
},
14+
}),
15+
},
16+
})
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { defineNuxtConfig } from 'nuxt/config'
2+
3+
export default defineNuxtConfig({
4+
modules: [
5+
'../../../src/module',
6+
],
7+
devtools: { enabled: true },
8+
compatibilityDate: '2025-09-03',
9+
})
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { eventHandler, getQuery } from 'h3'
2+
import { queryCollection } from '@nuxt/content/server'
3+
4+
export default eventHandler(async (event) => {
5+
const path = String(getQuery(event).path || '/')
6+
7+
const content = await queryCollection(event, 'content' as never).path(path).first()
8+
9+
return content
10+
})

test/remote-repository.test.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import fs from 'node:fs/promises'
2+
import { createResolver } from '@nuxt/kit'
3+
import { setup, $fetch } from '@nuxt/test-utils'
4+
import { afterAll, describe, expect, test } from 'vitest'
5+
6+
const resolver = createResolver(import.meta.url)
7+
8+
async function cleanup() {
9+
await fs.rm(resolver.resolve('./fixtures/remote-repository/node_modules'), { recursive: true, force: true })
10+
await fs.rm(resolver.resolve('./fixtures/remote-repository/.nuxt'), { recursive: true, force: true })
11+
await fs.rm(resolver.resolve('./fixtures/remote-repository/.data'), { recursive: true, force: true })
12+
await fs.rm(resolver.resolve('./fixtures/remote-repository/content'), { recursive: true, force: true })
13+
}
14+
15+
describe('remote-repository', async () => {
16+
await cleanup()
17+
afterAll(async () => {
18+
await cleanup()
19+
})
20+
21+
await setup({
22+
rootDir: resolver.resolve('./fixtures/remote-repository'),
23+
dev: true,
24+
})
25+
26+
describe('Repository', () => {
27+
test('is cloned', async () => {
28+
const stat = await fs.stat(resolver.resolve('./fixtures/remote-repository/.data/content/github-nuxt-content-main'))
29+
expect(stat?.isDirectory()).toBe(true)
30+
})
31+
})
32+
33+
describe('Content', () => {
34+
test('is loaded', async () => {
35+
const doc: Record<string, unknown> = await $fetch('/api/content/get?path=/docs/content')
36+
expect(doc).toBeDefined()
37+
expect(doc.path).toBe('/docs/content')
38+
})
39+
})
40+
})

0 commit comments

Comments
 (0)