Skip to content

Conversation

fry69
Copy link
Contributor

@fry69 fry69 commented Oct 5, 2025

Supersedes earlier attempt -> #3517

This is now ready for review.

The major upside and motivation for this template based approach is that it is now possible to view what gets generated in the repository as actual valid files including syntax highlighting and formatting.

Previously those files where just strings inside the old init script, which is IMHO a nightmare for maintainability.

The approach for this template system is loosely based on Vite's create-vite, which also includes (redundant) templates inside the repository, see here -> https://github.com/vitejs/vite/tree/main/packages/create-vite

Included in the tests are compatibility checks against the current @fresh/[email protected], those can get removed at a later point when the templates start to diverge. They are only included for demonstration purposes, that this new implementation generates 100% identical output.

This means that the first PR after this got included, which modifies the templates so the output differs from the old init script, also needs to include:

rm packages/init/tests/compatibility_test.ts

Since this is a rather large PR, it may be more approachable to view the branch directly -> https://github.com/fry69/fresh/tree/fry69/refactor-init-template-rename/packages/init

Generated PR message below:


Replaces inline string-based project generation with file-based templates for improved maintainability and extensibility.

Architecture

Template structure:

  • assets/template/ - Complete project templates (vite, vite-tailwind, builder, builder-tailwind)
  • assets/variants/ - Additive overlays (docker, vscode, vscode-tailwind)
  • assets/base/ - Common files synced across template variants

Templates use __VARIABLE__ syntax for substitution (project name, dependency versions). Files with __ prefix are renamed to . prefix during generation (e.g., __gitignore → .gitignore).

Template selection logic:

Base: vite|vite-tailwind|builder|builder-tailwind
Variants: +docker, +vscode, +vscode-tailwind

Maintenance workflow

Edit shared files in assets/base/vite/ or assets/base/builder/, then run deno task sync to propagate changes to template variants. Template-specific files (deno.json, vite.config.ts, styles.css) are never overwritten.

Version resolution

Matches existing behavior: only Fresh core version is fetched from JSR, all other dependencies use fixed versions updated by release scripts.

Testing

55 tests covering:

  • Unit tests for core functionality
  • Integration tests (project generation, builds, dev servers)
  • CLI argument parsing
  • Compatibility tests verifying output matches v2.0.9 (pre-refactor baseline)
  • Template sync workflow

Breaking changes

None. CLI interface and programmatic API remain identical. Package publishes to same @fresh/init scope at JSR.

Documentation

  • README.md - User-facing usage documentation
  • DESIGN.md - Maintainer documentation (architecture, template maintenance, development setup)

fry69 added 30 commits October 5, 2025 11:24
Migrated template system from .tmpl extensions to real file extensions
with unified __VAR__ substitution syntax (previously {{VAR}}).

Changes:
- Updated substitution regex in src/utils.ts to use __VAR__ format
- Modified src/init.ts to process all text files instead of only .tmpl
- Renamed all .tmpl files to use actual extensions (.ts, .tsx, .json)
- Updated all template files to use __VAR__ syntax
- Updated tests to reflect new syntax and file extensions
- Updated DESIGN.md with new conventions

Benefits:
- Proper syntax highlighting in all template files
- Editor auto-formatting and type checking now work
- Simpler processing logic without special extension handling
- Consistent variable syntax across all file types

All 45 tests passing.
marvinhagemeister pushed a commit that referenced this pull request Oct 6, 2025
This fixes issues I have with running tests on one of my servers, where
port 8000 on `localhost` is occupied.

Note: The current `init` test will continue to fail, but that will
hopefully get replaced by #3524 which does not have this problem.

Before:
```
[
  "error: Uncaught (in promise) AddrInUse: Address already in use (os error 98)",
  "    at listen (ext:deno_net/01_net.js:594:35)",
  "    at serveInner (ext:deno_http/00_serve.ts:675:16)",
  "    at Object.serve (ext:deno_http/00_serve.ts:591:10)",
  "    at ext:deno_http/00_serve.ts:819:10",
  "    at ext:runtime_main/js/99_main.js:708:13",
  "    at eventLoopTick (ext:core/01_core.js:179:7)"
]
[...]
Builder - write prod routePattern => ./packages/fresh/src/dev/builder_test.ts:284:6
Builder - file:// islands => ./packages/fresh/src/dev/builder_test.ts:319:6
Builder - serves static files in subdir in prod => ./packages/fresh/src/dev/builder_test.ts:474:6
init - can start built project => ./packages/init/src/init_test.ts:237:6

FAILED | 471 passed (14 steps) | 4 failed | 18 ignored
```

After:
```
ok | 475 passed (14 steps) | 0 failed | 18 ignored
```
Copy link
Collaborator

@marvinhagemeister marvinhagemeister left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@marvinhagemeister marvinhagemeister merged commit 198816b into denoland:main Oct 6, 2025
7 checks passed
marvinhagemeister added a commit that referenced this pull request Oct 6, 2025
marvinhagemeister added a commit that referenced this pull request Oct 6, 2025
marvinhagemeister added a commit that referenced this pull request Oct 6, 2025
#3524 unfortunately introduced a
regression in the init script which breaks it. This was caused by two
independent problems:

1. Only files reachable in the module graph are published, meaning the
templates itself weren't published to JSR
2. When publishing to JSR all specifiers become `https://` internally
which breaks doing path operations like `path.resolve()`,
`path.relative()` and all others. This is something that cannot be
tested locally in advance

Addressing these is going to require a bit of work. The quickest way to
get init working again is to revert it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants