Skip to content

Commit de07915

Browse files
authored
Merge branch 'main' into deps/upstream-update
2 parents 54b2b23 + 9f43d67 commit de07915

6 files changed

Lines changed: 108 additions & 45 deletions

File tree

.github/workflows/vp-binary-size.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ jobs:
153153
vp: `target/${target}/release/vp.exe`,
154154
napi: 'packages/cli/binding/vite-plus.win32-x64-msvc.node',
155155
trampoline: `target/${target}/release/vp-shim.exe`,
156+
installer: `target/${target}/release/vp-setup.exe`,
156157
};
157158
158159
const artifacts = {};
@@ -301,6 +302,13 @@ jobs:
301302
headRaw: headWindows.artifacts.trampoline.raw,
302303
headGzip: headWindows.artifacts.trampoline.gzip,
303304
},
305+
{
306+
name: 'Installer (Windows x64)',
307+
baseRaw: baseWindows.artifacts.installer.raw,
308+
baseGzip: baseWindows.artifacts.installer.gzip,
309+
headRaw: headWindows.artifacts.installer.raw,
310+
headGzip: headWindows.artifacts.installer.gzip,
311+
},
304312
];
305313
306314
const formatSize = (bytes, includePlus = false) => {

crates/vite_cli_snapshots/tests/cli_snapshots/fixtures/create_org_bundled_monorepo/snapshots/create_org_bundled_monorepo.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,9 @@ node_modules excluded even though tarball shipped no .gitignore
6666

6767
```
6868
node_modules
69+
70+
# dotenv environment variable files
71+
.env
72+
.env.*
73+
!.env.example
6974
```

packages/cli/src/create/__tests__/utils.spec.ts

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest';
66

77
import {
88
deriveDefaultPackageName,
9-
ensureGitignoreNodeModules,
9+
ensureDefaultGitignoreEntries,
1010
ensureGitignoreVsCodeEditorConfigs,
1111
formatTargetDir,
1212
getProjectDirFromPackageName,
@@ -124,7 +124,7 @@ describe('deriveDefaultPackageName', () => {
124124
});
125125
});
126126

127-
describe('ensureGitignoreNodeModules', () => {
127+
describe('ensureDefaultGitignoreEntries', () => {
128128
let projectDir: string;
129129

130130
beforeEach(() => {
@@ -139,54 +139,67 @@ describe('ensureGitignoreNodeModules', () => {
139139
return fs.readFileSync(path.join(projectDir, '.gitignore'), 'utf-8');
140140
}
141141

142-
it('creates a fresh `.gitignore` with `node_modules` when none exists', () => {
143-
ensureGitignoreNodeModules(projectDir);
144-
expect(gitignore()).toBe('node_modules\n');
142+
const dotenvBlock = '# dotenv environment variable files\n.env\n.env.*\n!.env.example\n';
143+
144+
it('creates a fresh `.gitignore` with default entries when none exists', () => {
145+
ensureDefaultGitignoreEntries(projectDir);
146+
expect(gitignore()).toBe(`node_modules\n\n${dotenvBlock}`);
145147
});
146148

147-
it('appends `node_modules` to an existing `.gitignore` that omits it', () => {
149+
it('appends default entries to an existing `.gitignore` that omits them', () => {
148150
fs.writeFileSync(path.join(projectDir, '.gitignore'), 'dist\n*.log\n');
149-
ensureGitignoreNodeModules(projectDir);
150-
expect(gitignore()).toBe('dist\n*.log\nnode_modules\n');
151+
ensureDefaultGitignoreEntries(projectDir);
152+
expect(gitignore()).toBe(`dist\n*.log\nnode_modules\n\n${dotenvBlock}`);
151153
});
152154

153155
it('terminates the last line first when the existing file lacks a trailing newline', () => {
154156
fs.writeFileSync(path.join(projectDir, '.gitignore'), 'dist');
155-
ensureGitignoreNodeModules(projectDir);
156-
expect(gitignore()).toBe('dist\nnode_modules\n');
157+
ensureDefaultGitignoreEntries(projectDir);
158+
expect(gitignore()).toBe(`dist\nnode_modules\n\n${dotenvBlock}`);
157159
});
158160

159-
it('is a no-op when `node_modules` already appears as a standalone line', () => {
161+
it('appends dotenv entries when `node_modules` already appears as a standalone line', () => {
160162
const existing = '# Logs\n*.log\nnode_modules\ndist\n';
161163
fs.writeFileSync(path.join(projectDir, '.gitignore'), existing);
162-
ensureGitignoreNodeModules(projectDir);
163-
expect(gitignore()).toBe(existing);
164+
ensureDefaultGitignoreEntries(projectDir);
165+
expect(gitignore()).toBe(`${existing}\n${dotenvBlock}`);
164166
});
165167

166168
it('treats `node_modules/` (with trailing slash) as a match', () => {
167169
const existing = 'node_modules/\ndist\n';
168170
fs.writeFileSync(path.join(projectDir, '.gitignore'), existing);
169-
ensureGitignoreNodeModules(projectDir);
170-
expect(gitignore()).toBe(existing);
171+
ensureDefaultGitignoreEntries(projectDir);
172+
expect(gitignore()).toBe(`${existing}\n${dotenvBlock}`);
171173
});
172174

173-
it('handles CRLF line endings without re-appending', () => {
174-
const existing = 'node_modules\r\ndist\r\n';
175+
it('handles CRLF line endings without re-appending existing defaults', () => {
176+
const existing = `node_modules\r\ndist\r\n${dotenvBlock.replaceAll('\n', '\r\n')}`;
175177
fs.writeFileSync(path.join(projectDir, '.gitignore'), existing);
176-
ensureGitignoreNodeModules(projectDir);
178+
ensureDefaultGitignoreEntries(projectDir);
177179
expect(gitignore()).toBe(existing);
178180
});
179181

180182
it('does not consider a `node_modules/sub` subpath as already excluded', () => {
181183
fs.writeFileSync(path.join(projectDir, '.gitignore'), 'node_modules/sub\n');
182-
ensureGitignoreNodeModules(projectDir);
183-
expect(gitignore()).toBe('node_modules/sub\nnode_modules\n');
184+
ensureDefaultGitignoreEntries(projectDir);
185+
expect(gitignore()).toBe(`node_modules/sub\nnode_modules\n\n${dotenvBlock}`);
184186
});
185187

186188
it('does not match `!node_modules` (an explicit un-ignore override)', () => {
187189
fs.writeFileSync(path.join(projectDir, '.gitignore'), '!node_modules\n');
188-
ensureGitignoreNodeModules(projectDir);
189-
expect(gitignore()).toBe('!node_modules\nnode_modules\n');
190+
ensureDefaultGitignoreEntries(projectDir);
191+
expect(gitignore()).toBe(`!node_modules\nnode_modules\n\n${dotenvBlock}`);
192+
});
193+
194+
it('adds only missing dotenv entries', () => {
195+
fs.writeFileSync(
196+
path.join(projectDir, '.gitignore'),
197+
'# dotenv environment variable files\n.env\nnode_modules\n',
198+
);
199+
ensureDefaultGitignoreEntries(projectDir);
200+
expect(gitignore()).toBe(
201+
'# dotenv environment variable files\n.env\nnode_modules\n.env.*\n!.env.example\n',
202+
);
190203
});
191204
});
192205

packages/cli/src/create/bin.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ import {
8484
import { BuiltinTemplate, TemplateType } from './templates/types.ts';
8585
import {
8686
deriveDefaultPackageName,
87-
ensureGitignoreNodeModules,
87+
ensureDefaultGitignoreEntries,
8888
ensureGitignoreVsCodeEditorConfigs,
8989
formatTargetDir,
9090
normalizeEditorOption,
@@ -1073,7 +1073,7 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
10731073
if (!compactOutput) {
10741074
prompts.log.success('Git repository initialized');
10751075
}
1076-
ensureGitignoreNodeModules(fullPath);
1076+
ensureDefaultGitignoreEntries(fullPath);
10771077
} else {
10781078
prompts.log.warn('Failed to initialize git repository');
10791079
if (gitResult.stderr) {
@@ -1111,7 +1111,9 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
11111111
rewriteMonorepo(workspaceInfo, undefined, compactOutput);
11121112
if (shouldSetupGit) {
11131113
updateCreateProgress('Initializing git repository');
1114-
await initGitRepository(fullPath);
1114+
if (await initGitRepository(fullPath)) {
1115+
ensureDefaultGitignoreEntries(fullPath);
1116+
}
11151117
}
11161118
if (bundled?.monorepo) {
11171119
// Wire `create.defaultTemplate: '<scope>'` into the new workspace's
@@ -1434,7 +1436,9 @@ Use \`vp create --list\` to list all available templates, or run \`vp create --h
14341436
}
14351437
if (shouldSetupGit) {
14361438
updateCreateProgress('Initializing git repository');
1437-
await initGitRepository(fullPath);
1439+
if (await initGitRepository(fullPath)) {
1440+
ensureDefaultGitignoreEntries(fullPath);
1441+
}
14381442
}
14391443
if (shouldSetupHooks) {
14401444
installGitHooks(fullPath, compactOutput, undefined, workspaceInfo.packageManager);

packages/cli/src/create/utils.ts

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -161,27 +161,67 @@ export function renameFiles(projectDir: string): void {
161161
}
162162
}
163163

164+
const DOTENV_GITIGNORE_LINES = [
165+
'# dotenv environment variable files',
166+
'.env',
167+
'.env.*',
168+
'!.env.example',
169+
] as const;
170+
164171
/**
165-
* Make sure the scaffolded project's `.gitignore` excludes `node_modules`.
172+
* Make sure the scaffolded project's `.gitignore` excludes default generated
173+
* project artifacts.
166174
*
167175
* Called right after `git init` so even bundled `@org` templates (which
168-
* may ship without a `.gitignore`) don't end up tracking installed
169-
* dependencies on the user's first commit. No-op when an existing
170-
* `.gitignore` already lists `node_modules`.
176+
* may ship without a `.gitignore`) don't end up tracking dependencies or
177+
* local environment files on the user's first commit.
171178
*/
172-
export function ensureGitignoreNodeModules(projectDir: string): void {
179+
export function ensureDefaultGitignoreEntries(projectDir: string): void {
173180
const gitignorePath = path.join(projectDir, '.gitignore');
174181
let content = '';
175182
try {
176183
content = fs.readFileSync(gitignorePath, 'utf-8');
177184
} catch {
178185
// No existing .gitignore — we'll write a fresh one below.
179186
}
180-
if (/^\s*node_modules\/?\s*$/m.test(content)) {
187+
188+
const lines: string[] = [];
189+
if (!hasNodeModulesGitignoreLine(content)) {
190+
lines.push('node_modules');
191+
}
192+
193+
const missingDotenvLines = DOTENV_GITIGNORE_LINES.filter(
194+
(line) => !hasGitignoreLine(content, line),
195+
);
196+
if (missingDotenvLines.length > 0) {
197+
const startsDotenvSection = missingDotenvLines[0] === DOTENV_GITIGNORE_LINES[0];
198+
if (lines.length > 0 || (startsDotenvSection && content.trim() !== '')) {
199+
lines.push('');
200+
}
201+
lines.push(...missingDotenvLines);
202+
}
203+
204+
appendGitignoreLines(gitignorePath, content, lines);
205+
}
206+
207+
function hasNodeModulesGitignoreLine(content: string): boolean {
208+
return /^\s*node_modules\/?\s*$/m.test(content);
209+
}
210+
211+
function hasGitignoreLine(content: string, line: string): boolean {
212+
return content.split(/\r?\n/).some((entry) => entry.trim() === line);
213+
}
214+
215+
function appendGitignoreLines(
216+
gitignorePath: string,
217+
content: string,
218+
lines: readonly string[],
219+
): void {
220+
if (lines.length === 0) {
181221
return;
182222
}
183223
const prefix = content === '' || content.endsWith('\n') ? '' : '\n';
184-
fs.appendFileSync(gitignorePath, `${prefix}node_modules\n`);
224+
fs.appendFileSync(gitignorePath, `${prefix}${lines.join('\n')}\n`);
185225
}
186226

187227
const VSCODE_SETTINGS_PATH = '.vscode/settings.json';
@@ -218,18 +258,6 @@ function appendGitignoreVsCodeEditorConfigsBlock(gitignorePath: string, content:
218258
appendGitignoreLines(gitignorePath, content, VSCODE_CONFIG_UNIGNORE_BLOCK);
219259
}
220260

221-
function appendGitignoreLines(
222-
gitignorePath: string,
223-
content: string,
224-
lines: readonly string[],
225-
): void {
226-
if (lines.length === 0) {
227-
return;
228-
}
229-
const prefix = content === '' || content.endsWith('\n') ? '' : '\n';
230-
fs.appendFileSync(gitignorePath, `${prefix}${lines.join('\n')}\n`);
231-
}
232-
233261
export function formatDisplayTargetDir(targetDir: string) {
234262
const normalized = targetDir.split(path.sep).join('/');
235263
if (normalized === '' || normalized === '.') {

packages/cli/templates/monorepo/_gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ dist
1212
dist-ssr
1313
*.local
1414

15+
# dotenv environment variable files
16+
.env
17+
.env.*
18+
!.env.example
19+
1520
# Editor directories and files
1621
.vscode/*
1722
!.vscode/settings.json

0 commit comments

Comments
 (0)