Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ba76c2f9a | |||
| 5c53602842 | |||
| 31f7cb98ea | |||
| c66af4e66c | |||
| 070bc7891e | |||
| a01b3ee122 | |||
| 5b7ba79724 | |||
| 060f107216 | |||
| 6dd7d6e093 | |||
| cd53bdb6f4 | |||
| 1bb05bfd2e | |||
| 94aff06cbc |
66
.gitea/workflows/default_nottags.yaml
Normal file
66
.gitea/workflows/default_nottags.yaml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
name: Default (not tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags-ignore:
|
||||||
|
- '**'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Install pnpm and npmci
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @ship.zone/npmci
|
||||||
|
|
||||||
|
- name: Run npm prepare
|
||||||
|
run: npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
124
.gitea/workflows/default_tags.yaml
Normal file
124
.gitea/workflows/default_tags.yaml
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
name: Default (tags)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
env:
|
||||||
|
IMAGE: code.foss.global/host.today/ht-docker-node:npmci
|
||||||
|
NPMCI_COMPUTED_REPOURL: https://${{gitea.repository_owner}}:${{secrets.GITEA_TOKEN}}@/${{gitea.repository}}.git
|
||||||
|
NPMCI_TOKEN_NPM: ${{secrets.NPMCI_TOKEN_NPM}}
|
||||||
|
NPMCI_TOKEN_NPM2: ${{secrets.NPMCI_TOKEN_NPM2}}
|
||||||
|
NPMCI_GIT_GITHUBTOKEN: ${{secrets.NPMCI_GIT_GITHUBTOKEN}}
|
||||||
|
NPMCI_URL_CLOUDLY: ${{secrets.NPMCI_URL_CLOUDLY}}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
security:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @ship.zone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Audit production dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --prod
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Audit development dependencies
|
||||||
|
run: |
|
||||||
|
npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
npmci command pnpm audit --audit-level=high --dev
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
test:
|
||||||
|
if: ${{ always() }}
|
||||||
|
needs: security
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @ship.zone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Test stable
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm test
|
||||||
|
|
||||||
|
- name: Test build
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
npmci npm build
|
||||||
|
|
||||||
|
release:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @ship.zone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Release
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm publish
|
||||||
|
|
||||||
|
metadata:
|
||||||
|
needs: test
|
||||||
|
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ${{ env.IMAGE }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Prepare
|
||||||
|
run: |
|
||||||
|
pnpm install -g pnpm
|
||||||
|
pnpm install -g @ship.zone/npmci
|
||||||
|
npmci npm prepare
|
||||||
|
|
||||||
|
- name: Code quality
|
||||||
|
run: |
|
||||||
|
npmci command npm install -g typescript
|
||||||
|
npmci npm install
|
||||||
|
|
||||||
|
- name: Trigger
|
||||||
|
run: npmci trigger
|
||||||
|
|
||||||
|
- name: Build docs and upload artifacts
|
||||||
|
run: |
|
||||||
|
npmci node install stable
|
||||||
|
npmci npm install
|
||||||
|
pnpm install -g @git.zone/tsdoc
|
||||||
|
npmci command tsdoc
|
||||||
|
continue-on-error: true
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -3,7 +3,6 @@
|
|||||||
# artifacts
|
# artifacts
|
||||||
coverage/
|
coverage/
|
||||||
public/
|
public/
|
||||||
pages/
|
|
||||||
|
|
||||||
# installs
|
# installs
|
||||||
node_modules/
|
node_modules/
|
||||||
@@ -17,4 +16,8 @@ node_modules/
|
|||||||
dist/
|
dist/
|
||||||
dist_*/
|
dist_*/
|
||||||
|
|
||||||
# custom
|
# AI
|
||||||
|
.claude/
|
||||||
|
.serena/
|
||||||
|
|
||||||
|
#------# custom
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"target": "ES2022",
|
||||||
"target": "ES2020",
|
"module": "ES2022",
|
||||||
"module": "ES2020",
|
|
||||||
"moduleResolution": "node12",
|
"moduleResolution": "node12",
|
||||||
"useDefineForClassFields": false,
|
|
||||||
"preserveValueImports": true,
|
"preserveValueImports": true,
|
||||||
"esModuleInterop": true
|
"esModuleInterop": true
|
||||||
}
|
}
|
||||||
|
|||||||
66
changelog.md
66
changelog.md
@@ -1,6 +1,56 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-01-11 - 2.7.0 - feat(tsbundle)
|
||||||
|
add npmextra-driven custom bundles, base64-ts output and interactive init wizard
|
||||||
|
|
||||||
|
- Add CustomBundleHandler to process bundle configs from npmextra.json (ts/mod_custom/*)
|
||||||
|
- Implement Base64TsOutput for embedding bundled files as base64 TypeScript (ts/mod_output/*)
|
||||||
|
- Add interactive 'init' wizard to scaffold npmextra.json bundle presets (ts/mod_init/*)
|
||||||
|
- Wire new features into CLI: default command runs custom bundles, added 'custom' and 'init' commands (ts/tsbundle.cli.ts)
|
||||||
|
- Expose @push.rocks/npmextra and @push.rocks/smartinteract in plugins and add them to package.json dependencies
|
||||||
|
- Update npmextra.json structure and release registries configuration
|
||||||
|
|
||||||
|
## 2025-12-02 - 2.6.3 - fix(cli)
|
||||||
|
Use basename when collecting HTML files for the website CLI command to ensure correct relative paths
|
||||||
|
|
||||||
|
- ts/tsbundle.cli.ts: use plugins.path.basename(entry.path) when building htmlFiles list instead of full entry.path
|
||||||
|
- Prevents incorrect paths when calling HtmlHandler.processHtml with './html/<file>' and ensures HTML files are processed from the expected relative html directory
|
||||||
|
|
||||||
|
## 2025-11-30 - 2.6.2 - fix(deps)
|
||||||
|
Bump dependencies and migrate test fixtures to ts_web
|
||||||
|
|
||||||
|
- Bumped devDependencies: @git.zone/tsbuild ^3.1.0 -> ^3.1.2, @types/node ^22.12.0 -> ^24.10.1
|
||||||
|
- Bumped runtime dependencies: @push.rocks/smartfs ^1.1.0 -> ^1.1.3, @rspack/core ^1.6.4 -> ^1.6.5, rolldown 1.0.0-beta.51 -> 1.0.0-beta.52
|
||||||
|
- Reworked tests: removed test/test-decorators.ts and test/ts_web/test-lit.ts; added test/ts_web/fixture-decorators.ts and test/ts_web/fixture-lit.ts (moved fixtures into ts_web)
|
||||||
|
- Updated package.json to include the dependency version bumps
|
||||||
|
|
||||||
|
## 2025-11-23 - 2.6.1 - fix(license)
|
||||||
|
Update copyright holder in license to Task Venture Capital GmbH
|
||||||
|
|
||||||
|
- Replaced the copyright owner in the license file from Lossless GmbH to Task Venture Capital GmbH
|
||||||
|
|
||||||
|
## 2025-11-23 - 2.6.0 - feat(core)
|
||||||
|
Integrate Rolldown as optional bundler, migrate filesystem to smartfs, and update bundler/tooling
|
||||||
|
|
||||||
|
- Add optional 'rolldown' bundler and wiring in TsBundle (supports --bundler=rolldown)
|
||||||
|
- Migrate filesystem usage from @push.rocks/smartfile to @push.rocks/smartfs and provide a shared async SmartFs instance
|
||||||
|
- Refactor HtmlHandler and AssetsHandler to use async smartfs APIs and improve HTML/asset processing (create dirs, write files, delete/replace targets)
|
||||||
|
- Update bundler child processes to read tsconfig async for alias resolution and normalize argument handling
|
||||||
|
- Bump dev and runtime dependencies: tsbuild, tsrun, tstest, rolldown, rspack, esbuild, typescript and related packages
|
||||||
|
- Add repository/metadata fields and pnpm section to package.json
|
||||||
|
- Add CI workflow definitions (.gitea/workflows) and docs build script (buildDocs)
|
||||||
|
- Update TypeScript config target to ES2022, adjust module settings and baseUrl/paths
|
||||||
|
- Small test and formatting fixes (test runners, HTML test, decorator test output formatting)
|
||||||
|
|
||||||
|
## 2025-11-17 - 2.5.2 - fix(tsconfig)
|
||||||
|
|
||||||
|
Update TypeScript configs to ES2022 and remove deprecated compiler flags
|
||||||
|
|
||||||
|
- assets/tsconfig.json: set target and module to ES2022 (was ES2020)
|
||||||
|
- assets/tsconfig.json and tsconfig.json: remove experimentalDecorators and useDefineForClassFields flags to align with updated TS setup
|
||||||
|
|
||||||
## 2025-06-26 - 2.5.1 - fix(readme)
|
## 2025-06-26 - 2.5.1 - fix(readme)
|
||||||
|
|
||||||
Update license and legal information section in readme
|
Update license and legal information section in readme
|
||||||
|
|
||||||
- Replaced contribution guidelines with detailed legal and trademark information
|
- Replaced contribution guidelines with detailed legal and trademark information
|
||||||
@@ -8,6 +58,7 @@ Update license and legal information section in readme
|
|||||||
- Added company information for Task Venture Capital GmbH
|
- Added company information for Task Venture Capital GmbH
|
||||||
|
|
||||||
## 2025-06-26 - 2.5.0 - feat(documentation)
|
## 2025-06-26 - 2.5.0 - feat(documentation)
|
||||||
|
|
||||||
Improve README with comprehensive installation, usage, and API reference details
|
Improve README with comprehensive installation, usage, and API reference details
|
||||||
|
|
||||||
- Updated installation instructions for both global and local setups
|
- Updated installation instructions for both global and local setups
|
||||||
@@ -17,12 +68,14 @@ Improve README with comprehensive installation, usage, and API reference details
|
|||||||
- Reorganized content to improve clarity and best practices guidance
|
- Reorganized content to improve clarity and best practices guidance
|
||||||
|
|
||||||
## 2025-06-26 - 2.4.1 - fix(tests)
|
## 2025-06-26 - 2.4.1 - fix(tests)
|
||||||
|
|
||||||
Improve decorator tests and add LitElement component tests for better validation
|
Improve decorator tests and add LitElement component tests for better validation
|
||||||
|
|
||||||
- Refactored test-decorators.ts to robustly verify that the sealed decorator prevents prototype modifications
|
- Refactored test-decorators.ts to robustly verify that the sealed decorator prevents prototype modifications
|
||||||
- Added test-lit.ts to ensure LitElement component renders correctly and increments counter on click
|
- Added test-lit.ts to ensure LitElement component renders correctly and increments counter on click
|
||||||
|
|
||||||
## 2025-06-19 - 2.4.0 - feat(bundler)
|
## 2025-06-19 - 2.4.0 - feat(bundler)
|
||||||
|
|
||||||
Introduce rspack bundler support and update multi-bundler workflow
|
Introduce rspack bundler support and update multi-bundler workflow
|
||||||
|
|
||||||
- Added full support for rspack with its own implementation in ts/mod_rspack
|
- Added full support for rspack with its own implementation in ts/mod_rspack
|
||||||
@@ -32,6 +85,7 @@ Introduce rspack bundler support and update multi-bundler workflow
|
|||||||
- Adjusted output configuration for esbuild and rolldown for dynamic naming and inline dynamic imports
|
- Adjusted output configuration for esbuild and rolldown for dynamic naming and inline dynamic imports
|
||||||
|
|
||||||
## 2025-06-19 - 2.3.0 - feat(bundler)
|
## 2025-06-19 - 2.3.0 - feat(bundler)
|
||||||
|
|
||||||
Integrate rolldown bundler support and update bundler selection logic
|
Integrate rolldown bundler support and update bundler selection logic
|
||||||
|
|
||||||
- Added rolldown dependency to package.json
|
- Added rolldown dependency to package.json
|
||||||
@@ -41,39 +95,46 @@ Integrate rolldown bundler support and update bundler selection logic
|
|||||||
- Revised readme and hints documentation for rolldown usage
|
- Revised readme and hints documentation for rolldown usage
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.5 - fix(mod_assets)
|
## 2025-01-29 - 2.2.5 - fix(mod_assets)
|
||||||
|
|
||||||
Fix async handling in asset processing
|
Fix async handling in asset processing
|
||||||
|
|
||||||
- Ensured that the empty directory operation is awaited in the asset processing workflow.
|
- Ensured that the empty directory operation is awaited in the asset processing workflow.
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.4 - fix(mod_assets)
|
## 2025-01-29 - 2.2.4 - fix(mod_assets)
|
||||||
|
|
||||||
Fix logging message in ensureAssetsDir to correctly state when directory is created
|
Fix logging message in ensureAssetsDir to correctly state when directory is created
|
||||||
|
|
||||||
- Corrected logging output in ensureAssetsDir method to indicate directory creation.
|
- Corrected logging output in ensureAssetsDir method to indicate directory creation.
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.3 - fix(mod_assets)
|
## 2025-01-29 - 2.2.3 - fix(mod_assets)
|
||||||
|
|
||||||
Fix issue with asset directory copy
|
Fix issue with asset directory copy
|
||||||
|
|
||||||
- Updated dependency '@push.rocks/smartfile' to version '^11.2.0'
|
- Updated dependency '@push.rocks/smartfile' to version '^11.2.0'
|
||||||
- Ensure target directory is properly replaced when copying assets
|
- Ensure target directory is properly replaced when copying assets
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.2 - fix(dependencies)
|
## 2025-01-29 - 2.2.2 - fix(dependencies)
|
||||||
|
|
||||||
Update smartfile dependency and fix spacing issue in assets module
|
Update smartfile dependency and fix spacing issue in assets module
|
||||||
|
|
||||||
- Updated @push.rocks/smartfile from ^11.1.6 to ^11.1.8
|
- Updated @push.rocks/smartfile from ^11.1.6 to ^11.1.8
|
||||||
- Fixed a spacing issue in the processAssets function within the assets module
|
- Fixed a spacing issue in the processAssets function within the assets module
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.1 - fix(index)
|
## 2025-01-29 - 2.2.1 - fix(index)
|
||||||
|
|
||||||
Export mod_assets for programmatic use
|
Export mod_assets for programmatic use
|
||||||
|
|
||||||
- Added export for mod_assets/index in ts/index.ts to make it usable programmatically.
|
- Added export for mod_assets/index in ts/index.ts to make it usable programmatically.
|
||||||
|
|
||||||
## 2025-01-29 - 2.2.0 - feat(AssetsHandler)
|
## 2025-01-29 - 2.2.0 - feat(AssetsHandler)
|
||||||
|
|
||||||
Add asset handling to the CLI workflow
|
Add asset handling to the CLI workflow
|
||||||
|
|
||||||
- Introduced AssetsHandler class for managing asset directories and files.
|
- Introduced AssetsHandler class for managing asset directories and files.
|
||||||
- Updated tsbundle.cli.ts to include asset processing in the 'website' command.
|
- Updated tsbundle.cli.ts to include asset processing in the 'website' command.
|
||||||
|
|
||||||
## 2025-01-28 - 2.1.1 - fix(core)
|
## 2025-01-28 - 2.1.1 - fix(core)
|
||||||
|
|
||||||
Update dependencies and remove GitLab CI configuration.
|
Update dependencies and remove GitLab CI configuration.
|
||||||
|
|
||||||
- Updated several devDependencies to newer versions for improved stability and performance.
|
- Updated several devDependencies to newer versions for improved stability and performance.
|
||||||
@@ -81,24 +142,27 @@ Update dependencies and remove GitLab CI configuration.
|
|||||||
- Removed the .gitlab-ci.yml file, which could suggest a change in continuous integration setup.
|
- Removed the .gitlab-ci.yml file, which could suggest a change in continuous integration setup.
|
||||||
|
|
||||||
## 2024-10-27 - 2.1.0 - feat(mod_esbuild)
|
## 2024-10-27 - 2.1.0 - feat(mod_esbuild)
|
||||||
|
|
||||||
Add alias support to esbuild bundling process
|
Add alias support to esbuild bundling process
|
||||||
|
|
||||||
- Updated dependencies in package.json to latest versions.
|
- Updated dependencies in package.json to latest versions.
|
||||||
- Improved build process by adding alias resolution based on tsconfig.json settings in esbuild.
|
- Improved build process by adding alias resolution based on tsconfig.json settings in esbuild.
|
||||||
|
|
||||||
## 2022-05-04 - 2.0.0-2.0.1 - Breaking and Fix Changes
|
## 2022-05-04 - 2.0.0-2.0.1 - Breaking and Fix Changes
|
||||||
|
|
||||||
Released version 2.0.0 with breaking changes and subsequent fixes.
|
Released version 2.0.0 with breaking changes and subsequent fixes.
|
||||||
|
|
||||||
- BREAKING CHANGE(core): Removed parcel and rollup
|
- BREAKING CHANGE(core): Removed parcel and rollup
|
||||||
- fix(core): Addressed initial issues in new major version
|
- fix(core): Addressed initial issues in new major version
|
||||||
|
|
||||||
## 2023-10-03 - 2.0.10 - Fix Updates
|
## 2023-10-03 - 2.0.10 - Fix Updates
|
||||||
|
|
||||||
Ongoing updates and improvements.
|
Ongoing updates and improvements.
|
||||||
|
|
||||||
- fix(core): General updates and enhancements
|
- fix(core): General updates and enhancements
|
||||||
|
|
||||||
## 2024-01-10 - 2.0.11-2.0.15 - Minor Fixes
|
## 2024-01-10 - 2.0.11-2.0.15 - Minor Fixes
|
||||||
|
|
||||||
Cumulative fixes and updates from recent releases.
|
Cumulative fixes and updates from recent releases.
|
||||||
|
|
||||||
- fix(core): Continuous improvement cycle across versions
|
- fix(core): Continuous improvement cycle across versions
|
||||||
|
|
||||||
|
|||||||
2
license
2
license
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2019 Lossless GmbH (hello@lossless.com)
|
Copyright (c) 2019 Task Venture Capital GmbH (hello@task.vc)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"gitzone": {
|
"@git.zone/cli": {
|
||||||
"projectType": "npm",
|
"projectType": "npm",
|
||||||
"module": {
|
"module": {
|
||||||
"githost": "gitlab.com",
|
"githost": "gitlab.com",
|
||||||
@@ -9,10 +9,16 @@
|
|||||||
"npmPackagename": "@git.zone/tsbundle",
|
"npmPackagename": "@git.zone/tsbundle",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"projectDomain": "git.zone"
|
"projectDomain": "git.zone"
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"registries": [
|
||||||
|
"https://verdaccio.lossless.one",
|
||||||
|
"https://registry.npmjs.org"
|
||||||
|
],
|
||||||
|
"accessLevel": "public"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"npmci": {
|
"@ship.zone/szci": {
|
||||||
"npmGlobalTools": [],
|
"npmGlobalTools": []
|
||||||
"npmAccessLevel": "public"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
45
package.json
45
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@git.zone/tsbundle",
|
"name": "@git.zone/tsbundle",
|
||||||
"version": "2.5.1",
|
"version": "2.7.0",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects",
|
"description": "a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@@ -10,34 +10,36 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run build && (tstest test/ --verbose)",
|
"test": "npm run build && (tstest test/ --verbose)",
|
||||||
"build": "(tsbuild --web --allowimplicitany)"
|
"build": "(tsbuild --web --allowimplicitany)",
|
||||||
|
"buildDocs": "tsdoc"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsbundle": "cli.js"
|
"tsbundle": "cli.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@git.zone/tsbuild": "^2.6.4",
|
"@git.zone/tsbuild": "^3.1.2",
|
||||||
"@git.zone/tsrun": "^1.3.3",
|
"@git.zone/tsrun": "^2.0.0",
|
||||||
"@git.zone/tstest": "^2.3.1",
|
"@git.zone/tstest": "^3.1.3",
|
||||||
"@push.rocks/tapbundle": "^6.0.3",
|
"@types/node": "^24.10.1"
|
||||||
"@types/node": "^22.12.0"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@push.rocks/early": "^4.0.4",
|
"@push.rocks/early": "^4.0.4",
|
||||||
"@push.rocks/smartcli": "^4.0.11",
|
"@push.rocks/npmextra": "^5.1.3",
|
||||||
|
"@push.rocks/smartcli": "^4.0.19",
|
||||||
|
"@push.rocks/smartinteract": "^2.0.16",
|
||||||
"@push.rocks/smartdelay": "^3.0.5",
|
"@push.rocks/smartdelay": "^3.0.5",
|
||||||
"@push.rocks/smartfile": "^11.2.5",
|
"@push.rocks/smartfs": "^1.1.3",
|
||||||
"@push.rocks/smartlog": "^3.1.8",
|
"@push.rocks/smartlog": "^3.1.8",
|
||||||
"@push.rocks/smartlog-destination-local": "^9.0.2",
|
"@push.rocks/smartlog-destination-local": "^9.0.2",
|
||||||
"@push.rocks/smartpath": "^5.0.18",
|
"@push.rocks/smartpath": "^6.0.0",
|
||||||
"@push.rocks/smartpromise": "^4.2.3",
|
"@push.rocks/smartpromise": "^4.2.3",
|
||||||
"@push.rocks/smartspawn": "^3.0.3",
|
"@push.rocks/smartspawn": "^3.0.3",
|
||||||
"@types/html-minifier": "^4.0.5",
|
"@rspack/core": "^1.6.5",
|
||||||
"esbuild": "^0.25.5",
|
"@types/html-minifier": "^4.0.6",
|
||||||
|
"esbuild": "^0.27.0",
|
||||||
"html-minifier": "^4.0.0",
|
"html-minifier": "^4.0.0",
|
||||||
"rolldown": "^1.0.0-beta.18",
|
"rolldown": "1.0.0-beta.52",
|
||||||
"@rspack/core": "^1.1.8",
|
"typescript": "5.9.3"
|
||||||
"typescript": "5.8.3"
|
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"ts/**/*",
|
"ts/**/*",
|
||||||
@@ -54,5 +56,16 @@
|
|||||||
"browserslist": [
|
"browserslist": [
|
||||||
"last 1 chrome versions"
|
"last 1 chrome versions"
|
||||||
],
|
],
|
||||||
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://gitlab.com/gitzone/tsbundle.git"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://gitlab.com/gitzone/tsbundle/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://gitlab.com/gitzone/tsbundle#readme",
|
||||||
|
"pnpm": {
|
||||||
|
"overrides": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8123
pnpm-lock.yaml
generated
8123
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,19 +1,31 @@
|
|||||||
# tsbundle Hints and Findings
|
# tsbundle Hints and Findings
|
||||||
|
|
||||||
|
## Recent Updates (2025-11-23)
|
||||||
|
|
||||||
|
- Migrated from @push.rocks/smartfile v11 to @push.rocks/smartfs v1.1.0
|
||||||
|
- All filesystem operations now use async smartfs API
|
||||||
|
- Removed @push.rocks/tapbundle (now imported from @git.zone/tstest/tapbundle)
|
||||||
|
- All bundlers (esbuild, rolldown, rspack) updated to latest versions
|
||||||
|
- Removed deprecated rolldown experimental.enableComposingJsPlugins option
|
||||||
|
|
||||||
## Bundler Architecture
|
## Bundler Architecture
|
||||||
|
|
||||||
- tsbundle uses a child process architecture where each bundler runs in a separate process
|
- tsbundle uses a child process architecture where each bundler runs in a separate process
|
||||||
- Configuration is passed via environment variables as JSON (IEnvTransportOptions)
|
- Configuration is passed via environment variables as JSON (IEnvTransportOptions)
|
||||||
- The main class `TsBundle` spawns child processes using `smartspawn.ThreadSimple`
|
- The main class `TsBundle` spawns child processes using `smartspawn.ThreadSimple`
|
||||||
|
|
||||||
## Bundler Implementations
|
## Bundler Implementations
|
||||||
- **esbuild** (default): Fully implemented, production ready, 2.2K minified
|
|
||||||
- **rolldown**: Implemented and working (beta), produces smallest bundles (1.5K minified)
|
- **esbuild** (default): Fully implemented, production ready, 3.9K minified
|
||||||
- **rspack**: Implemented and working, webpack-compatible API, 6.1K minified
|
- **rolldown**: Implemented and working (beta v1.0.0-beta.51), produces smallest bundles (1.0K minified)
|
||||||
|
- **rspack**: Implemented and working (v1.6.4), webpack-compatible API, 6.3K minified
|
||||||
- **rollup**: Removed (was never implemented)
|
- **rollup**: Removed (was never implemented)
|
||||||
- **parcel**: Removed (was never implemented)
|
- **parcel**: Removed (was never implemented)
|
||||||
|
|
||||||
## Adding New Bundlers
|
## Adding New Bundlers
|
||||||
|
|
||||||
To add a new bundler, you need:
|
To add a new bundler, you need:
|
||||||
|
|
||||||
1. Update `ICliOptions` interface to include the bundler name
|
1. Update `ICliOptions` interface to include the bundler name
|
||||||
2. Add case in `getBundlerPath()` switch statement
|
2. Add case in `getBundlerPath()` switch statement
|
||||||
3. Create `mod_<bundler>/` directory with:
|
3. Create `mod_<bundler>/` directory with:
|
||||||
@@ -22,6 +34,7 @@ To add a new bundler, you need:
|
|||||||
4. Add bundler to package.json dependencies
|
4. Add bundler to package.json dependencies
|
||||||
|
|
||||||
## Rolldown Specific Notes
|
## Rolldown Specific Notes
|
||||||
|
|
||||||
- Rolldown is in beta (v1.0.0-beta.18) but working well
|
- Rolldown is in beta (v1.0.0-beta.18) but working well
|
||||||
- API: Use `rolldown()` function directly, not `rolldown.rolldown()`
|
- API: Use `rolldown()` function directly, not `rolldown.rolldown()`
|
||||||
- Output options go in the `write()` method, not the initial config
|
- Output options go in the `write()` method, not the initial config
|
||||||
@@ -31,6 +44,7 @@ To add a new bundler, you need:
|
|||||||
- Supports TypeScript via `resolve.tsconfigFilename`
|
- Supports TypeScript via `resolve.tsconfigFilename`
|
||||||
|
|
||||||
## Rspack Specific Notes
|
## Rspack Specific Notes
|
||||||
|
|
||||||
- Rspack v1.3.15 - stable and production ready
|
- Rspack v1.3.15 - stable and production ready
|
||||||
- Uses webpack-compatible API (callback-based)
|
- Uses webpack-compatible API (callback-based)
|
||||||
- Built-in SWC loader for TypeScript transpilation
|
- Built-in SWC loader for TypeScript transpilation
|
||||||
@@ -39,11 +53,13 @@ To add a new bundler, you need:
|
|||||||
- Supports ES modules output via `experiments.outputModule: true`
|
- Supports ES modules output via `experiments.outputModule: true`
|
||||||
|
|
||||||
## CLI Usage
|
## CLI Usage
|
||||||
|
|
||||||
- Default bundler: `tsbundle` (uses esbuild)
|
- Default bundler: `tsbundle` (uses esbuild)
|
||||||
- Specify bundler: `tsbundle --bundler=rolldown` or `tsbundle --bundler=rspack`
|
- Specify bundler: `tsbundle --bundler=rolldown` or `tsbundle --bundler=rspack`
|
||||||
- Production mode: `tsbundle --production`
|
- Production mode: `tsbundle --production`
|
||||||
- Combined: `tsbundle --bundler=rolldown --production`
|
- Combined: `tsbundle --bundler=rolldown --production`
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
- esbuild recently had splitting and tree-shaking disabled due to issues
|
- esbuild recently had splitting and tree-shaking disabled due to issues
|
||||||
- The README still mentions "a bundler using rollup" but uses esbuild by default
|
- The README still mentions "a bundler using rollup" but uses esbuild by default
|
||||||
51
readme.md
51
readme.md
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
A powerful multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects.
|
A powerful multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects.
|
||||||
|
|
||||||
|
## Issue Reporting and Security
|
||||||
|
|
||||||
|
For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -44,19 +48,14 @@ await bundler.build(
|
|||||||
process.cwd(), // working directory
|
process.cwd(), // working directory
|
||||||
'./src/index.ts', // entry point
|
'./src/index.ts', // entry point
|
||||||
'./dist/bundle.js', // output file
|
'./dist/bundle.js', // output file
|
||||||
{ bundler: 'esbuild' } // options
|
{ bundler: 'esbuild' }, // options
|
||||||
);
|
);
|
||||||
|
|
||||||
// Production build with rolldown
|
// Production build with rolldown
|
||||||
await bundler.build(
|
await bundler.build(process.cwd(), './src/index.ts', './dist/bundle.min.js', {
|
||||||
process.cwd(),
|
|
||||||
'./src/index.ts',
|
|
||||||
'./dist/bundle.min.js',
|
|
||||||
{
|
|
||||||
bundler: 'rolldown',
|
bundler: 'rolldown',
|
||||||
production: true
|
production: true,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Available Bundlers
|
## Available Bundlers
|
||||||
@@ -163,7 +162,7 @@ const exists = await htmlHandler.checkIfExists();
|
|||||||
await htmlHandler.processHtml({
|
await htmlHandler.processHtml({
|
||||||
from: './src/index.html', // Source HTML (default: './html/index.html')
|
from: './src/index.html', // Source HTML (default: './html/index.html')
|
||||||
to: './dist/index.html', // Output HTML (default: './dist_serve/index.html')
|
to: './dist/index.html', // Output HTML (default: './dist_serve/index.html')
|
||||||
minify: true // Enable minification
|
minify: true, // Enable minification
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -182,7 +181,7 @@ await assetsHandler.ensureAssetsDir();
|
|||||||
// Copy and process assets
|
// Copy and process assets
|
||||||
await assetsHandler.processAssets({
|
await assetsHandler.processAssets({
|
||||||
from: './src/assets', // Source directory (default: './assets')
|
from: './src/assets', // Source directory (default: './assets')
|
||||||
to: './dist/assets' // Output directory (default: './dist_serve/assets')
|
to: './dist/assets', // Output directory (default: './dist_serve/assets')
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -199,27 +198,22 @@ async function buildWebApp() {
|
|||||||
const assetsHandler = new AssetsHandler();
|
const assetsHandler = new AssetsHandler();
|
||||||
|
|
||||||
// Bundle the JavaScript
|
// Bundle the JavaScript
|
||||||
await bundler.build(
|
await bundler.build(process.cwd(), './src/app.ts', './dist/app.js', {
|
||||||
process.cwd(),
|
|
||||||
'./src/app.ts',
|
|
||||||
'./dist/app.js',
|
|
||||||
{
|
|
||||||
bundler: 'rolldown',
|
bundler: 'rolldown',
|
||||||
production: true
|
production: true,
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Process HTML
|
// Process HTML
|
||||||
await htmlHandler.processHtml({
|
await htmlHandler.processHtml({
|
||||||
from: './src/index.html',
|
from: './src/index.html',
|
||||||
to: './dist/index.html',
|
to: './dist/index.html',
|
||||||
minify: true
|
minify: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Copy assets
|
// Copy assets
|
||||||
await assetsHandler.processAssets({
|
await assetsHandler.processAssets({
|
||||||
from: './src/assets',
|
from: './src/assets',
|
||||||
to: './dist/assets'
|
to: './dist/assets',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Build complete!');
|
console.log('Build complete!');
|
||||||
@@ -238,16 +232,13 @@ async function buildMultipleEntries() {
|
|||||||
const entries = [
|
const entries = [
|
||||||
{ from: './src/main.ts', to: './dist/main.js' },
|
{ from: './src/main.ts', to: './dist/main.js' },
|
||||||
{ from: './src/admin.ts', to: './dist/admin.js' },
|
{ from: './src/admin.ts', to: './dist/admin.js' },
|
||||||
{ from: './src/worker.ts', to: './dist/worker.js' }
|
{ from: './src/worker.ts', to: './dist/worker.js' },
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
await bundler.build(
|
await bundler.build(process.cwd(), entry.from, entry.to, {
|
||||||
process.cwd(),
|
bundler: 'esbuild',
|
||||||
entry.from,
|
});
|
||||||
entry.to,
|
|
||||||
{ bundler: 'esbuild' }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -267,8 +258,8 @@ await bundler.build(
|
|||||||
{
|
{
|
||||||
bundler: isDev ? 'esbuild' : 'rolldown', // esbuild for speed in dev
|
bundler: isDev ? 'esbuild' : 'rolldown', // esbuild for speed in dev
|
||||||
production: !isDev, // minify in production
|
production: !isDev, // minify in production
|
||||||
commonjs: false // use ES modules
|
commonjs: false, // use ES modules
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
**Command to reread CLAUDE.md**: `cat ~/.claude/CLAUDE.md`
|
**Command to reread CLAUDE.md**: `cat ~/.claude/CLAUDE.md`
|
||||||
|
|
||||||
## Objective
|
## Objective
|
||||||
|
|
||||||
Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the default bundler. This allows users to experiment with Rolldown using `--bundler=rolldown` flag.
|
Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the default bundler. This allows users to experiment with Rolldown using `--bundler=rolldown` flag.
|
||||||
|
|
||||||
## Current State
|
## Current State
|
||||||
|
|
||||||
- tsbundle currently only uses esbuild despite having interfaces for multiple bundlers
|
- tsbundle currently only uses esbuild despite having interfaces for multiple bundlers
|
||||||
- The bundler selection logic exists but always returns esbuild
|
- The bundler selection logic exists but always returns esbuild
|
||||||
- mod_rollup and mod_parcel directories exist but are empty
|
- mod_rollup and mod_parcel directories exist but are empty
|
||||||
@@ -14,23 +16,26 @@ Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the def
|
|||||||
## Implementation Tasks
|
## Implementation Tasks
|
||||||
|
|
||||||
### Phase 1: Core Infrastructure
|
### Phase 1: Core Infrastructure
|
||||||
|
|
||||||
- [x] Update `ts/interfaces/index.ts` to include 'rolldown' in bundler union type
|
- [x] Update `ts/interfaces/index.ts` to include 'rolldown' in bundler union type
|
||||||
- [x] Fix `getBundlerPath()` in `ts/tsbundle.class.tsbundle.ts` to properly route bundlers
|
- [x] Fix `getBundlerPath()` in `ts/tsbundle.class.tsbundle.ts` to properly route bundlers
|
||||||
- [x] Remove hardcoded `bundler: 'esbuild'` from transportOptions (line 26)
|
- [x] Remove hardcoded `bundler: 'esbuild'` from transportOptions (line 26)
|
||||||
- [x] Add rolldown dependency to package.json: `"rolldown": "^1.0.0-beta.18"`
|
- [x] Add rolldown dependency to package.json: `"rolldown": "^1.0.0-beta.18"`
|
||||||
|
|
||||||
### Phase 2: CLI Support
|
### Phase 2: CLI Support
|
||||||
|
|
||||||
- [x] Check if `ts/tsbundle.cli.ts` already parses --bundler option
|
- [x] Check if `ts/tsbundle.cli.ts` already parses --bundler option
|
||||||
- [x] Ensure default bundler is 'esbuild' when not specified
|
- [x] Ensure default bundler is 'esbuild' when not specified
|
||||||
- [x] Verify CLI passes bundler option correctly to TsBundle class
|
- [x] Verify CLI passes bundler option correctly to TsBundle class
|
||||||
|
|
||||||
### Phase 3: Rolldown Module Implementation
|
### Phase 3: Rolldown Module Implementation
|
||||||
|
|
||||||
- [x] Create `ts/mod_rolldown/` directory
|
- [x] Create `ts/mod_rolldown/` directory
|
||||||
- [x] Create `ts/mod_rolldown/plugins.ts`:
|
- [x] Create `ts/mod_rolldown/plugins.ts`:
|
||||||
```typescript
|
```typescript
|
||||||
export * from '../plugins.js';
|
export * from '../plugins.js';
|
||||||
import { rolldown } from 'rolldown';
|
import { rolldown } from 'rolldown';
|
||||||
export { rolldown }
|
export { rolldown };
|
||||||
```
|
```
|
||||||
- [x] Create `ts/mod_rolldown/index.child.ts` with:
|
- [x] Create `ts/mod_rolldown/index.child.ts` with:
|
||||||
- TsBundleProcess class
|
- TsBundleProcess class
|
||||||
@@ -40,6 +45,7 @@ Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the def
|
|||||||
- run() function to read transportOptions and execute
|
- run() function to read transportOptions and execute
|
||||||
|
|
||||||
### Phase 4: Feature Parity
|
### Phase 4: Feature Parity
|
||||||
|
|
||||||
- [x] Implement TypeScript compilation via rolldown
|
- [x] Implement TypeScript compilation via rolldown
|
||||||
- [x] Ensure source map generation works
|
- [x] Ensure source map generation works
|
||||||
- [x] Support tsconfig path aliases
|
- [x] Support tsconfig path aliases
|
||||||
@@ -48,6 +54,7 @@ Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the def
|
|||||||
- [x] Handle bundle: true behavior
|
- [x] Handle bundle: true behavior
|
||||||
|
|
||||||
### Phase 5: Testing
|
### Phase 5: Testing
|
||||||
|
|
||||||
- [x] Test default behavior (should use esbuild)
|
- [x] Test default behavior (should use esbuild)
|
||||||
- [x] Test `--bundler=esbuild` explicit selection
|
- [x] Test `--bundler=esbuild` explicit selection
|
||||||
- [x] Test `--bundler=rolldown` selection
|
- [x] Test `--bundler=rolldown` selection
|
||||||
@@ -57,8 +64,9 @@ Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the def
|
|||||||
## Technical Specifications
|
## Technical Specifications
|
||||||
|
|
||||||
### Rolldown Configuration Mapping
|
### Rolldown Configuration Mapping
|
||||||
|
|
||||||
| esbuild option | rolldown equivalent |
|
| esbuild option | rolldown equivalent |
|
||||||
|----------------|-------------------|
|
| ---------------- | ----------------------------------- |
|
||||||
| bundle: true | bundle: true |
|
| bundle: true | bundle: true |
|
||||||
| sourcemap: true | sourcemap: true |
|
| sourcemap: true | sourcemap: true |
|
||||||
| format: 'esm' | format: 'es' |
|
| format: 'esm' | format: 'es' |
|
||||||
@@ -70,6 +78,7 @@ Add Rolldown as an optional bundler to tsbundle while keeping esbuild as the def
|
|||||||
| alias | resolve.alias |
|
| alias | resolve.alias |
|
||||||
|
|
||||||
### CLI Usage
|
### CLI Usage
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Default (uses esbuild)
|
# Default (uses esbuild)
|
||||||
tsbundle
|
tsbundle
|
||||||
@@ -82,12 +91,14 @@ tsbundle --production --bundler=rolldown
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Risks and Mitigation
|
## Risks and Mitigation
|
||||||
|
|
||||||
1. **Rolldown is beta** - Keep esbuild as default, mark rolldown as experimental
|
1. **Rolldown is beta** - Keep esbuild as default, mark rolldown as experimental
|
||||||
2. **API differences** - Abstract common interface, handle bundler-specific logic
|
2. **API differences** - Abstract common interface, handle bundler-specific logic
|
||||||
3. **Missing features** - Document any limitations in README
|
3. **Missing features** - Document any limitations in README
|
||||||
4. **Breaking changes** - None, as esbuild remains default
|
4. **Breaking changes** - None, as esbuild remains default
|
||||||
|
|
||||||
## Success Criteria
|
## Success Criteria
|
||||||
|
|
||||||
- [x] Can build with esbuild (default behavior unchanged)
|
- [x] Can build with esbuild (default behavior unchanged)
|
||||||
- [x] Can build with rolldown via --bundler flag
|
- [x] Can build with rolldown via --bundler flag
|
||||||
- [x] Both bundlers produce working ESM output
|
- [x] Both bundlers produce working ESM output
|
||||||
@@ -96,9 +107,11 @@ tsbundle --production --bundler=rolldown
|
|||||||
- [ ] All existing tests pass
|
- [ ] All existing tests pass
|
||||||
|
|
||||||
## Implementation Status
|
## Implementation Status
|
||||||
|
|
||||||
✅ **COMPLETED** - Rolldown has been successfully integrated as an optional bundler.
|
✅ **COMPLETED** - Rolldown has been successfully integrated as an optional bundler.
|
||||||
|
|
||||||
### Test Results:
|
### Test Results:
|
||||||
|
|
||||||
- esbuild (default): Working correctly, 2.2K minified
|
- esbuild (default): Working correctly, 2.2K minified
|
||||||
- rolldown: Working correctly, 1.5K minified (better compression!)
|
- rolldown: Working correctly, 1.5K minified (better compression!)
|
||||||
- Both bundlers support all required features
|
- Both bundlers support all required features
|
||||||
@@ -106,6 +119,7 @@ tsbundle --production --bundler=rolldown
|
|||||||
- Production and test modes work for both
|
- Production and test modes work for both
|
||||||
|
|
||||||
## Future Considerations
|
## Future Considerations
|
||||||
|
|
||||||
- Once Rolldown reaches v1.0.0 stable, consider making it default
|
- Once Rolldown reaches v1.0.0 stable, consider making it default
|
||||||
- Implement rollup and parcel modules using same pattern
|
- Implement rollup and parcel modules using same pattern
|
||||||
- Add performance benchmarks comparing bundlers
|
- Add performance benchmarks comparing bundlers
|
||||||
|
|||||||
@@ -15,7 +15,10 @@
|
|||||||
|
|
||||||
<!--Lets make sure we support older browsers-->
|
<!--Lets make sure we support older browsers-->
|
||||||
<script src=" https://unpkg.com/@webcomponents/webcomponentsjs@^2/webcomponents-bundle.js"></script>
|
<script src=" https://unpkg.com/@webcomponents/webcomponentsjs@^2/webcomponents-bundle.js"></script>
|
||||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet" />
|
<link
|
||||||
|
href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
|
||||||
<!--Lets avoid a rescaling flicker due to default body margins-->
|
<!--Lets avoid a rescaling flicker due to default body margins-->
|
||||||
<style>
|
<style>
|
||||||
@@ -62,13 +65,11 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="header">
|
<div class="header">We need JavaScript to run properly!</div>
|
||||||
We need JavaScript to run properly!
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
<div class="content">
|
||||||
This site is being built using lit-element (made by Google). This technology works with
|
This site is being built using lit-element (made by Google). This
|
||||||
JavaScript. Subsequently this website does not work as intended by Lossless GmbH without
|
technology works with JavaScript. Subsequently this website does not
|
||||||
JavaScript.
|
work as intended by Lossless GmbH without JavaScript.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
|
|||||||
@@ -1,41 +0,0 @@
|
|||||||
// Test file to verify decorator functionality
|
|
||||||
function sealed(constructor: Function) {
|
|
||||||
Object.seal(constructor);
|
|
||||||
Object.seal(constructor.prototype);
|
|
||||||
}
|
|
||||||
|
|
||||||
@sealed
|
|
||||||
class TestClass {
|
|
||||||
name = 'test';
|
|
||||||
|
|
||||||
modify() {
|
|
||||||
this.name = 'modified';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that the class is sealed
|
|
||||||
const instance = new TestClass();
|
|
||||||
console.log('Initial name:', instance.name);
|
|
||||||
|
|
||||||
// This should work (modifying existing property)
|
|
||||||
instance.modify();
|
|
||||||
console.log('Modified name:', instance.name);
|
|
||||||
|
|
||||||
// This should fail silently in non-strict mode or throw in strict mode
|
|
||||||
try {
|
|
||||||
(instance as any).newProperty = 'should not work';
|
|
||||||
console.log('Adding new property:', (instance as any).newProperty);
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Error adding property (expected):', e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test that we can't add to prototype
|
|
||||||
try {
|
|
||||||
(TestClass.prototype as any).newMethod = function() {};
|
|
||||||
console.log('Prototype is NOT sealed (unexpected)');
|
|
||||||
} catch (e) {
|
|
||||||
console.log('Prototype is sealed (expected)');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Is TestClass sealed?', Object.isSealed(TestClass));
|
|
||||||
console.log('Is TestClass.prototype sealed?', Object.isSealed(TestClass.prototype));
|
|
||||||
22
test/test.ts
22
test/test.ts
@@ -3,7 +3,10 @@ import * as tsbundle from '../dist_ts/index.js';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
|
|
||||||
const testBundler = async (bundlerName: 'esbuild' | 'rolldown' | 'rspack', mode: 'test' | 'production') => {
|
const testBundler = async (
|
||||||
|
bundlerName: 'esbuild' | 'rolldown' | 'rspack',
|
||||||
|
mode: 'test' | 'production',
|
||||||
|
) => {
|
||||||
const outputFile = `./dist_manual/${bundlerName}-${mode}.js`;
|
const outputFile = `./dist_manual/${bundlerName}-${mode}.js`;
|
||||||
const testDir = path.join(process.cwd(), 'test');
|
const testDir = path.join(process.cwd(), 'test');
|
||||||
|
|
||||||
@@ -20,15 +23,10 @@ const testBundler = async (bundlerName: 'esbuild' | 'rolldown' | 'rspack', mode:
|
|||||||
}
|
}
|
||||||
|
|
||||||
const tsbundleInstance = new tsbundle.TsBundle();
|
const tsbundleInstance = new tsbundle.TsBundle();
|
||||||
await tsbundleInstance.build(
|
await tsbundleInstance.build(testDir, './ts_web/index.ts', outputFile, {
|
||||||
testDir,
|
|
||||||
'./ts_web/index.ts',
|
|
||||||
outputFile,
|
|
||||||
{
|
|
||||||
bundler: bundlerName,
|
bundler: bundlerName,
|
||||||
production: mode === 'production'
|
production: mode === 'production',
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
// Verify output file was created
|
// Verify output file was created
|
||||||
expect(fs.existsSync(outputPath)).toBeTrue();
|
expect(fs.existsSync(outputPath)).toBeTrue();
|
||||||
@@ -69,7 +67,7 @@ tap.test('should show bundle size comparison', async () => {
|
|||||||
const sizes: Record<string, { test: number; production: number }> = {
|
const sizes: Record<string, { test: number; production: number }> = {
|
||||||
esbuild: { test: 0, production: 0 },
|
esbuild: { test: 0, production: 0 },
|
||||||
rolldown: { test: 0, production: 0 },
|
rolldown: { test: 0, production: 0 },
|
||||||
rspack: { test: 0, production: 0 }
|
rspack: { test: 0, production: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
|
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
|
||||||
@@ -89,7 +87,9 @@ tap.test('should show bundle size comparison', async () => {
|
|||||||
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
|
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
|
||||||
const testSize = (sizes[bundler].test / 1024).toFixed(1) + ' KB';
|
const testSize = (sizes[bundler].test / 1024).toFixed(1) + ' KB';
|
||||||
const prodSize = (sizes[bundler].production / 1024).toFixed(1) + ' KB';
|
const prodSize = (sizes[bundler].production / 1024).toFixed(1) + ' KB';
|
||||||
console.log(`│ ${bundler.padEnd(11)} │ ${testSize.padEnd(10)} │ ${prodSize.padEnd(12)} │`);
|
console.log(
|
||||||
|
`│ ${bundler.padEnd(11)} │ ${testSize.padEnd(10)} │ ${prodSize.padEnd(12)} │`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
console.log('└─────────────┴────────────┴──────────────┘');
|
console.log('└─────────────┴────────────┴──────────────┘');
|
||||||
|
|
||||||
|
|||||||
36
test/ts_web/fixture-decorators.ts
Normal file
36
test/ts_web/fixture-decorators.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Test file to verify decorator functionality
|
||||||
|
const decoratedClasses: Function[] = [];
|
||||||
|
|
||||||
|
function trackClass(constructor: Function) {
|
||||||
|
decoratedClasses.push(constructor);
|
||||||
|
return constructor;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logMethod(_target: any, context: ClassMethodDecoratorContext) {
|
||||||
|
const methodName = String(context.name);
|
||||||
|
return function (this: any, ...args: any[]) {
|
||||||
|
console.log(`Calling method: ${methodName}`);
|
||||||
|
return (_target as Function).apply(this, args);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@trackClass
|
||||||
|
class TestClass {
|
||||||
|
name = 'test';
|
||||||
|
|
||||||
|
@logMethod
|
||||||
|
modify() {
|
||||||
|
this.name = 'modified';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that the class decorator worked
|
||||||
|
const instance = new TestClass();
|
||||||
|
console.log('Initial name:', instance.name);
|
||||||
|
console.log('Class was decorated:', decoratedClasses.includes(TestClass));
|
||||||
|
|
||||||
|
// Test that the method decorator worked
|
||||||
|
instance.modify();
|
||||||
|
console.log('Modified name:', instance.name);
|
||||||
|
|
||||||
|
console.log('Decorator test completed successfully!');
|
||||||
@@ -19,9 +19,7 @@ export class MyElement extends LitElement {
|
|||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<h1>Hello, ${this.name}!</h1>
|
<h1>Hello, ${this.name}!</h1>
|
||||||
<button @click=${this._onClick}>
|
<button @click=${this._onClick}>Click Count: ${this.count}</button>
|
||||||
Click Count: ${this.count}
|
|
||||||
</button>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -19,6 +19,4 @@ class BugReport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
console.log(myConst);
|
console.log(myConst);
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/tsbundle',
|
name: '@git.zone/tsbundle',
|
||||||
version: '2.5.1',
|
version: '2.7.0',
|
||||||
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
|
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,35 @@ export interface ICliOptions {
|
|||||||
commonjs?: boolean;
|
commonjs?: boolean;
|
||||||
skiplibcheck?: boolean;
|
skiplibcheck?: boolean;
|
||||||
production?: boolean;
|
production?: boolean;
|
||||||
bundler: 'esbuild' | 'rolldown' | 'rspack'
|
bundler: 'esbuild' | 'rolldown' | 'rspack';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEnvTransportOptions {
|
export interface IEnvTransportOptions {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
from: string;
|
from: string;
|
||||||
to: string;
|
to: string;
|
||||||
mode: 'test' | 'production',
|
mode: 'test' | 'production';
|
||||||
argv: ICliOptions
|
argv: ICliOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Custom bundle configuration types
|
||||||
|
export type TOutputMode = 'bundle' | 'base64ts';
|
||||||
|
export type TBundler = 'esbuild' | 'rolldown' | 'rspack';
|
||||||
|
|
||||||
|
export interface IBundleConfig {
|
||||||
|
from: string;
|
||||||
|
to: string;
|
||||||
|
outputMode?: TOutputMode;
|
||||||
|
bundler?: TBundler;
|
||||||
|
production?: boolean;
|
||||||
|
includeFiles?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITsbundleConfig {
|
||||||
|
bundles: IBundleConfig[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IBase64File {
|
||||||
|
path: string;
|
||||||
|
contentBase64: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,38 +3,66 @@ import * as paths from '../paths.js';
|
|||||||
|
|
||||||
export class AssetsHandler {
|
export class AssetsHandler {
|
||||||
public defaultFromDirPath: string = plugins.path.join(paths.cwd, './assets');
|
public defaultFromDirPath: string = plugins.path.join(paths.cwd, './assets');
|
||||||
public defaultToDirPath: string = plugins.path.join(paths.cwd, './dist_serve/assets');
|
public defaultToDirPath: string = plugins.path.join(
|
||||||
|
paths.cwd,
|
||||||
|
'./dist_serve/assets',
|
||||||
|
);
|
||||||
|
|
||||||
public async ensureAssetsDir() {
|
public async ensureAssetsDir() {
|
||||||
const assetsDirExists = await plugins.smartfile.fs.isDirectory(this.defaultFromDirPath);
|
const dirExists = await plugins.fs
|
||||||
if (!assetsDirExists) {
|
.directory(this.defaultFromDirPath)
|
||||||
await plugins.smartfile.fs.ensureDir(this.defaultFromDirPath);
|
.exists();
|
||||||
|
if (!dirExists) {
|
||||||
|
await plugins.fs.directory(this.defaultFromDirPath).create();
|
||||||
console.log(`created assets directory at ${this.defaultFromDirPath}`);
|
console.log(`created assets directory at ${this.defaultFromDirPath}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copies the assets directory recursively
|
||||||
|
private async copyDirectoryRecursive(from: string, to: string) {
|
||||||
|
const entries = await plugins.fs.directory(from).recursive().list();
|
||||||
|
await plugins.fs.directory(to).create();
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fromPath = plugins.path.join(from, entry.path);
|
||||||
|
const toPath = plugins.path.join(to, entry.path);
|
||||||
|
|
||||||
|
if (entry.isDirectory) {
|
||||||
|
await plugins.fs.directory(toPath).create();
|
||||||
|
} else {
|
||||||
|
const toDir = plugins.path.dirname(toPath);
|
||||||
|
await plugins.fs.directory(toDir).create();
|
||||||
|
await plugins.fs.file(fromPath).copy(toPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// copies the html
|
// copies the html
|
||||||
public async processAssets(optionsArg?: {
|
public async processAssets(optionsArg?: { from?: string; to?: string }) {
|
||||||
from?: string;
|
|
||||||
to?: string;
|
|
||||||
}) {
|
|
||||||
// lets assemble the options
|
// lets assemble the options
|
||||||
optionsArg = {
|
optionsArg = {
|
||||||
...{
|
...{
|
||||||
from: this.defaultFromDirPath,
|
from: this.defaultFromDirPath,
|
||||||
to: this.defaultToDirPath,
|
to: this.defaultToDirPath,
|
||||||
},
|
},
|
||||||
...(optionsArg || {})
|
...(optionsArg || {}),
|
||||||
}
|
};
|
||||||
await this.ensureAssetsDir()
|
await this.ensureAssetsDir();
|
||||||
optionsArg.from = plugins.smartpath.transform.toAbsolute(optionsArg.from, paths.cwd) as string;
|
optionsArg.from = plugins.smartpath.transform.toAbsolute(
|
||||||
optionsArg.to = plugins.smartpath.transform.toAbsolute(optionsArg.to, paths.cwd) as string;
|
optionsArg.from,
|
||||||
|
paths.cwd,
|
||||||
|
) as string;
|
||||||
|
optionsArg.to = plugins.smartpath.transform.toAbsolute(
|
||||||
|
optionsArg.to,
|
||||||
|
paths.cwd,
|
||||||
|
) as string;
|
||||||
|
|
||||||
// lets clean theh target directory
|
// lets clean the target directory
|
||||||
await plugins.smartfile.fs.ensureEmptyDir(optionsArg.to);
|
const toExists = await plugins.fs.directory(optionsArg.to).exists();
|
||||||
|
if (toExists) {
|
||||||
|
await plugins.fs.directory(optionsArg.to).delete();
|
||||||
|
}
|
||||||
|
|
||||||
plugins.smartfile.fs.copySync(optionsArg.from, optionsArg.to, {
|
await this.copyDirectoryRecursive(optionsArg.from, optionsArg.to);
|
||||||
replaceTargetDir: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
203
ts/mod_custom/index.ts
Normal file
203
ts/mod_custom/index.ts
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as paths from '../paths.js';
|
||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
import { TsBundle } from '../tsbundle.class.tsbundle.js';
|
||||||
|
import { HtmlHandler } from '../mod_html/index.js';
|
||||||
|
import { Base64TsOutput } from '../mod_output/index.js';
|
||||||
|
|
||||||
|
const TEMP_DIR = '.nogit/tsbundle-temp';
|
||||||
|
|
||||||
|
export class CustomBundleHandler {
|
||||||
|
private cwd: string;
|
||||||
|
private config: interfaces.ITsbundleConfig;
|
||||||
|
|
||||||
|
constructor(cwd: string = paths.cwd) {
|
||||||
|
this.cwd = cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load configuration from npmextra.json
|
||||||
|
*/
|
||||||
|
public async loadConfig(): Promise<boolean> {
|
||||||
|
const npmextraInstance = new plugins.npmextra.Npmextra(this.cwd);
|
||||||
|
this.config = npmextraInstance.dataFor<interfaces.ITsbundleConfig>('@git.zone/tsbundle', {
|
||||||
|
bundles: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!this.config.bundles || this.config.bundles.length === 0) {
|
||||||
|
console.log('No bundle configuration found.');
|
||||||
|
console.log('Run `tsbundle init` to create one.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Found ${this.config.bundles.length} bundle configuration(s)`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process all configured bundles
|
||||||
|
*/
|
||||||
|
public async processAllBundles(): Promise<void> {
|
||||||
|
for (let i = 0; i < this.config.bundles.length; i++) {
|
||||||
|
const bundleConfig = this.config.bundles[i];
|
||||||
|
console.log(`\nProcessing bundle ${i + 1}/${this.config.bundles.length}: ${bundleConfig.from} -> ${bundleConfig.to}`);
|
||||||
|
await this.processSingleBundle(bundleConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a single bundle configuration
|
||||||
|
*/
|
||||||
|
private async processSingleBundle(bundleConfig: interfaces.IBundleConfig): Promise<void> {
|
||||||
|
const outputMode = bundleConfig.outputMode || 'bundle';
|
||||||
|
const bundler = bundleConfig.bundler || 'esbuild';
|
||||||
|
|
||||||
|
// Determine temp output path
|
||||||
|
const tempDir = plugins.path.join(this.cwd, TEMP_DIR);
|
||||||
|
const tempBundlePath = plugins.path.join(tempDir, `bundle-${Date.now()}.js`);
|
||||||
|
|
||||||
|
// Ensure temp directory exists
|
||||||
|
await plugins.fs.directory(tempDir).create();
|
||||||
|
|
||||||
|
// Build the bundle to temp location
|
||||||
|
const tsbundle = new TsBundle();
|
||||||
|
await tsbundle.build(
|
||||||
|
this.cwd,
|
||||||
|
bundleConfig.from,
|
||||||
|
tempBundlePath,
|
||||||
|
{
|
||||||
|
bundler,
|
||||||
|
production: bundleConfig.production || false,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (outputMode === 'base64ts') {
|
||||||
|
await this.handleBase64TsOutput(bundleConfig, tempBundlePath);
|
||||||
|
} else {
|
||||||
|
await this.handleBundleOutput(bundleConfig, tempBundlePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up temp file
|
||||||
|
const tempFileExists = await plugins.fs.file(tempBundlePath).exists();
|
||||||
|
if (tempFileExists) {
|
||||||
|
await plugins.fs.file(tempBundlePath).delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle base64ts output mode
|
||||||
|
*/
|
||||||
|
private async handleBase64TsOutput(
|
||||||
|
bundleConfig: interfaces.IBundleConfig,
|
||||||
|
tempBundlePath: string
|
||||||
|
): Promise<void> {
|
||||||
|
const base64Output = new Base64TsOutput(this.cwd);
|
||||||
|
|
||||||
|
// Add the bundle itself
|
||||||
|
const bundleContent = await plugins.fs.file(tempBundlePath).read();
|
||||||
|
base64Output.addFile('bundle.js', bundleContent);
|
||||||
|
|
||||||
|
// Add included files
|
||||||
|
if (bundleConfig.includeFiles && bundleConfig.includeFiles.length > 0) {
|
||||||
|
for (const pattern of bundleConfig.includeFiles) {
|
||||||
|
await base64Output.addFilesFromGlob(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the TypeScript output
|
||||||
|
await base64Output.writeToFile(bundleConfig.to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle standard bundle output mode
|
||||||
|
*/
|
||||||
|
private async handleBundleOutput(
|
||||||
|
bundleConfig: interfaces.IBundleConfig,
|
||||||
|
tempBundlePath: string
|
||||||
|
): Promise<void> {
|
||||||
|
// Move bundle to final destination
|
||||||
|
const toPath = plugins.smartpath.transform.toAbsolute(bundleConfig.to, this.cwd) as string;
|
||||||
|
const toDir = plugins.path.dirname(toPath);
|
||||||
|
await plugins.fs.directory(toDir).create();
|
||||||
|
|
||||||
|
const bundleContent = await plugins.fs.file(tempBundlePath).read();
|
||||||
|
await plugins.fs.file(toPath).write(bundleContent);
|
||||||
|
console.log(`Bundle written to: ${bundleConfig.to}`);
|
||||||
|
|
||||||
|
// Process included files (copy them)
|
||||||
|
if (bundleConfig.includeFiles && bundleConfig.includeFiles.length > 0) {
|
||||||
|
const htmlHandler = new HtmlHandler();
|
||||||
|
const outputDir = plugins.path.dirname(toPath);
|
||||||
|
|
||||||
|
for (const pattern of bundleConfig.includeFiles) {
|
||||||
|
await this.copyIncludedFiles(pattern, outputDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy files matching a pattern to the output directory
|
||||||
|
*/
|
||||||
|
private async copyIncludedFiles(pattern: string, outputDir: string): Promise<void> {
|
||||||
|
const absolutePattern = plugins.smartpath.transform.toAbsolute(pattern, this.cwd) as string;
|
||||||
|
const patternDir = plugins.path.dirname(absolutePattern);
|
||||||
|
const patternBase = plugins.path.basename(absolutePattern);
|
||||||
|
const isGlobPattern = patternBase.includes('*');
|
||||||
|
|
||||||
|
if (isGlobPattern) {
|
||||||
|
const dirPath = patternDir.replace(/\/\*\*$/, '');
|
||||||
|
const dirExists = await plugins.fs.directory(dirPath).exists();
|
||||||
|
if (!dirExists) {
|
||||||
|
console.log(`Directory does not exist: ${dirPath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRecursive = pattern.includes('**');
|
||||||
|
let entries;
|
||||||
|
if (isRecursive) {
|
||||||
|
entries = await plugins.fs.directory(dirPath).recursive().list();
|
||||||
|
} else {
|
||||||
|
entries = await plugins.fs.directory(dirPath).list();
|
||||||
|
}
|
||||||
|
|
||||||
|
const filePattern = patternBase.replace('*', '.*');
|
||||||
|
const regex = new RegExp(filePattern);
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (!entry.isDirectory && regex.test(entry.name)) {
|
||||||
|
const fullPath = plugins.path.join(dirPath, entry.path);
|
||||||
|
const relativePath = plugins.path.relative(this.cwd, fullPath);
|
||||||
|
const destPath = plugins.path.join(outputDir, plugins.path.basename(entry.path));
|
||||||
|
await plugins.fs.directory(plugins.path.dirname(destPath)).create();
|
||||||
|
await plugins.fs.file(fullPath).copy(destPath);
|
||||||
|
console.log(`Copied: ${relativePath} -> ${destPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const fileExists = await plugins.fs.file(absolutePattern).exists();
|
||||||
|
if (!fileExists) {
|
||||||
|
console.log(`File does not exist: ${absolutePattern}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const fileName = plugins.path.basename(absolutePattern);
|
||||||
|
const destPath = plugins.path.join(outputDir, fileName);
|
||||||
|
await plugins.fs.file(absolutePattern).copy(destPath);
|
||||||
|
console.log(`Copied: ${pattern} -> ${destPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the custom bundle command
|
||||||
|
*/
|
||||||
|
export async function runCustomBundles(): Promise<void> {
|
||||||
|
const handler = new CustomBundleHandler();
|
||||||
|
const hasConfig = await handler.loadConfig();
|
||||||
|
|
||||||
|
if (!hasConfig) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await handler.processAllBundles();
|
||||||
|
console.log('\nCustom bundle processing complete!');
|
||||||
|
}
|
||||||
1
ts/mod_custom/plugins.ts
Normal file
1
ts/mod_custom/plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../plugins.js';
|
||||||
@@ -11,10 +11,16 @@ export class TsBundleProcess {
|
|||||||
public async getAliases() {
|
public async getAliases() {
|
||||||
try {
|
try {
|
||||||
const aliasObject: Record<string, string> = {};
|
const aliasObject: Record<string, string> = {};
|
||||||
const localTsConfig = plugins.smartfile.fs.toObjectSync(
|
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
|
||||||
plugins.path.join(paths.cwd, 'tsconfig.json')
|
const tsconfigContent = await plugins.fs
|
||||||
);
|
.file(tsconfigPath)
|
||||||
if (localTsConfig.compilerOptions && localTsConfig.compilerOptions.paths) {
|
.encoding('utf8')
|
||||||
|
.read();
|
||||||
|
const localTsConfig = JSON.parse(tsconfigContent as string);
|
||||||
|
if (
|
||||||
|
localTsConfig.compilerOptions &&
|
||||||
|
localTsConfig.compilerOptions.paths
|
||||||
|
) {
|
||||||
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
||||||
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
||||||
aliasObject[alias] = aliasPath;
|
aliasObject[alias] = aliasPath;
|
||||||
@@ -75,7 +81,7 @@ export class TsBundleProcess {
|
|||||||
const run = async () => {
|
const run = async () => {
|
||||||
console.log('running spawned compilation process');
|
console.log('running spawned compilation process');
|
||||||
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
||||||
process.env.transportOptions
|
process.env.transportOptions,
|
||||||
);
|
);
|
||||||
console.log('=======> ESBUILD');
|
console.log('=======> ESBUILD');
|
||||||
console.log(transportOptions);
|
console.log(transportOptions);
|
||||||
@@ -85,16 +91,28 @@ const run = async () => {
|
|||||||
if (transportOptions.mode === 'test') {
|
if (transportOptions.mode === 'test') {
|
||||||
console.log('building for test:');
|
console.log('building for test:');
|
||||||
tsbundleProcessInstance.buildTest(
|
tsbundleProcessInstance.buildTest(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('building for production:');
|
console.log('building for production:');
|
||||||
tsbundleProcessInstance.buildProduction(
|
tsbundleProcessInstance.buildProduction(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,4 @@ export * from '../plugins.js';
|
|||||||
|
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
|
|
||||||
export {
|
export { esbuild };
|
||||||
esbuild
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ import * as plugins from './plugins.js';
|
|||||||
import * as paths from '../paths.js';
|
import * as paths from '../paths.js';
|
||||||
|
|
||||||
export class HtmlHandler {
|
export class HtmlHandler {
|
||||||
public defaultFromPath: string = plugins.path.join(paths.htmlDir, 'index.html');
|
public defaultFromPath: string = plugins.path.join(
|
||||||
public defaultToPath: string = plugins.path.join(paths.distServeDir, 'index.html');
|
paths.htmlDir,
|
||||||
|
'index.html',
|
||||||
|
);
|
||||||
|
public defaultToPath: string = plugins.path.join(
|
||||||
|
paths.distServeDir,
|
||||||
|
'index.html',
|
||||||
|
);
|
||||||
|
|
||||||
public async checkIfExists() {
|
public async checkIfExists() {
|
||||||
return plugins.smartfile.fs.fileExists(this.defaultFromPath);
|
return await plugins.fs.file(this.defaultFromPath).exists();
|
||||||
}
|
}
|
||||||
|
|
||||||
// copies the html
|
// copies the html
|
||||||
@@ -21,14 +27,23 @@ export class HtmlHandler {
|
|||||||
to: this.defaultToPath,
|
to: this.defaultToPath,
|
||||||
minify: false,
|
minify: false,
|
||||||
},
|
},
|
||||||
...optionsArg
|
...optionsArg,
|
||||||
}
|
};
|
||||||
if (await this.checkIfExists()) {
|
if (await this.checkIfExists()) {
|
||||||
console.log(`${optionsArg.from} replaces file at ${optionsArg.to}`);
|
console.log(`${optionsArg.from} replaces file at ${optionsArg.to}`);
|
||||||
}
|
}
|
||||||
optionsArg.from = plugins.smartpath.transform.toAbsolute(optionsArg.from, paths.cwd) as string;
|
optionsArg.from = plugins.smartpath.transform.toAbsolute(
|
||||||
optionsArg.to = plugins.smartpath.transform.toAbsolute(optionsArg.to, paths.cwd) as string;
|
optionsArg.from,
|
||||||
let fileString = plugins.smartfile.fs.toStringSync(optionsArg.from);
|
paths.cwd,
|
||||||
|
) as string;
|
||||||
|
optionsArg.to = plugins.smartpath.transform.toAbsolute(
|
||||||
|
optionsArg.to,
|
||||||
|
paths.cwd,
|
||||||
|
) as string;
|
||||||
|
let fileString = (await plugins.fs
|
||||||
|
.file(optionsArg.from)
|
||||||
|
.encoding('utf8')
|
||||||
|
.read()) as string;
|
||||||
if (optionsArg.minify) {
|
if (optionsArg.minify) {
|
||||||
fileString = plugins.htmlMinifier.minify(fileString, {
|
fileString = plugins.htmlMinifier.minify(fileString, {
|
||||||
minifyCSS: true,
|
minifyCSS: true,
|
||||||
@@ -41,7 +56,9 @@ export class HtmlHandler {
|
|||||||
removeComments: true,
|
removeComments: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await plugins.smartfile.memory.toFs(fileString, optionsArg.to);
|
const toDir = plugins.path.dirname(optionsArg.to);
|
||||||
|
await plugins.fs.directory(toDir).create();
|
||||||
|
await plugins.fs.file(optionsArg.to).encoding('utf8').write(fileString);
|
||||||
console.log(`html processing succeeded!`);
|
console.log(`html processing succeeded!`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,4 @@ export * from '../plugins.js';
|
|||||||
|
|
||||||
import * as htmlMinifier from 'html-minifier';
|
import * as htmlMinifier from 'html-minifier';
|
||||||
|
|
||||||
export {
|
export { htmlMinifier };
|
||||||
htmlMinifier
|
|
||||||
}
|
|
||||||
|
|||||||
377
ts/mod_init/index.ts
Normal file
377
ts/mod_init/index.ts
Normal file
@@ -0,0 +1,377 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as paths from '../paths.js';
|
||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
|
||||||
|
// Preset configurations
|
||||||
|
const PRESETS: Record<string, { description: string; config: interfaces.IBundleConfig }> = {
|
||||||
|
element: {
|
||||||
|
description: 'Web component / element bundle',
|
||||||
|
config: {
|
||||||
|
from: './ts_web/index.ts',
|
||||||
|
to: './dist_bundle/bundle.js',
|
||||||
|
outputMode: 'bundle',
|
||||||
|
bundler: 'esbuild',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
website: {
|
||||||
|
description: 'Full website with HTML and assets',
|
||||||
|
config: {
|
||||||
|
from: './ts_web/index.ts',
|
||||||
|
to: './dist_serve/bundle.js',
|
||||||
|
outputMode: 'bundle',
|
||||||
|
bundler: 'esbuild',
|
||||||
|
includeFiles: ['./html/**/*.html', './assets/**/*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
npm: {
|
||||||
|
description: 'NPM package bundle (from ts/)',
|
||||||
|
config: {
|
||||||
|
from: './ts/index.ts',
|
||||||
|
to: './dist_bundle/bundle.js',
|
||||||
|
outputMode: 'bundle',
|
||||||
|
bundler: 'esbuild',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export class InitHandler {
|
||||||
|
private cwd: string;
|
||||||
|
private npmextraPath: string;
|
||||||
|
|
||||||
|
constructor(cwd: string = paths.cwd) {
|
||||||
|
this.cwd = cwd;
|
||||||
|
this.npmextraPath = plugins.path.join(this.cwd, 'npmextra.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load existing npmextra.json or create empty config
|
||||||
|
*/
|
||||||
|
private async loadExistingConfig(): Promise<any> {
|
||||||
|
const fileExists = await plugins.fs.file(this.npmextraPath).exists();
|
||||||
|
if (fileExists) {
|
||||||
|
const content = (await plugins.fs.file(this.npmextraPath).encoding('utf8').read()) as string;
|
||||||
|
try {
|
||||||
|
return JSON.parse(content);
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save config to npmextra.json
|
||||||
|
*/
|
||||||
|
private async saveConfig(config: any): Promise<void> {
|
||||||
|
const content = JSON.stringify(config, null, 2);
|
||||||
|
await plugins.fs.file(this.npmextraPath).encoding('utf8').write(content);
|
||||||
|
console.log(`\n✅ Configuration saved to npmextra.json`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the interactive init wizard
|
||||||
|
*/
|
||||||
|
public async runWizard(): Promise<void> {
|
||||||
|
console.log('\n🚀 tsbundle configuration wizard\n');
|
||||||
|
console.log('This wizard will help you configure bundle settings in npmextra.json.\n');
|
||||||
|
|
||||||
|
const npmextraJson = await this.loadExistingConfig();
|
||||||
|
|
||||||
|
if (!npmextraJson['@git.zone/tsbundle']) {
|
||||||
|
npmextraJson['@git.zone/tsbundle'] = { bundles: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingBundles = npmextraJson['@git.zone/tsbundle'].bundles || [];
|
||||||
|
|
||||||
|
if (existingBundles.length > 0) {
|
||||||
|
console.log(`Found ${existingBundles.length} existing bundle configuration(s):\n`);
|
||||||
|
existingBundles.forEach((bundle: interfaces.IBundleConfig, i: number) => {
|
||||||
|
console.log(` ${i + 1}. ${bundle.from} → ${bundle.to} (${bundle.outputMode || 'bundle'})`);
|
||||||
|
});
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
let addMore = true;
|
||||||
|
while (addMore) {
|
||||||
|
const bundle = await this.configureSingleBundle();
|
||||||
|
if (bundle) {
|
||||||
|
npmextraJson['@git.zone/tsbundle'].bundles.push(bundle);
|
||||||
|
console.log(`\n✅ Bundle configuration added!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const continueInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
continueInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'addAnother',
|
||||||
|
message: 'Would you like to add another bundle configuration?',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const answers = await continueInteract.runQueue();
|
||||||
|
addMore = answers.getAnswerFor('addAnother');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.saveConfig(npmextraJson);
|
||||||
|
|
||||||
|
console.log('\n📋 Final configuration:\n');
|
||||||
|
const bundles = npmextraJson['@git.zone/tsbundle'].bundles;
|
||||||
|
bundles.forEach((bundle: interfaces.IBundleConfig, i: number) => {
|
||||||
|
console.log(` Bundle ${i + 1}:`);
|
||||||
|
console.log(` From: ${bundle.from}`);
|
||||||
|
console.log(` To: ${bundle.to}`);
|
||||||
|
console.log(` Mode: ${bundle.outputMode || 'bundle'}`);
|
||||||
|
console.log(` Bundler: ${bundle.bundler || 'esbuild'}`);
|
||||||
|
if (bundle.includeFiles && bundle.includeFiles.length > 0) {
|
||||||
|
console.log(` Include: ${bundle.includeFiles.join(', ')}`);
|
||||||
|
}
|
||||||
|
console.log('');
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('Run `tsbundle` to build your bundles.\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a single bundle interactively
|
||||||
|
*/
|
||||||
|
private async configureSingleBundle(): Promise<interfaces.IBundleConfig | null> {
|
||||||
|
// First, ask for preset or custom
|
||||||
|
const presetInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
presetInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'preset',
|
||||||
|
message: 'Choose a configuration:',
|
||||||
|
choices: [
|
||||||
|
{ name: 'element - Web component / element bundle', value: 'element' },
|
||||||
|
{ name: 'website - Full website with HTML and assets', value: 'website' },
|
||||||
|
{ name: 'npm - NPM package bundle (from ts/)', value: 'npm' },
|
||||||
|
{ name: 'custom - Configure manually', value: 'custom' },
|
||||||
|
],
|
||||||
|
default: 'element',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const presetAnswers = await presetInteract.runQueue();
|
||||||
|
const selectedPreset = presetAnswers.getAnswerFor('preset') as string;
|
||||||
|
|
||||||
|
// If custom, go to full manual configuration
|
||||||
|
if (selectedPreset === 'custom') {
|
||||||
|
return this.configureManualBundle();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show preset config and ask if user wants to use it or customize
|
||||||
|
const preset = PRESETS[selectedPreset];
|
||||||
|
console.log(`\n📦 ${preset.description}:`);
|
||||||
|
console.log(` From: ${preset.config.from}`);
|
||||||
|
console.log(` To: ${preset.config.to}`);
|
||||||
|
console.log(` Mode: ${preset.config.outputMode}`);
|
||||||
|
console.log(` Bundler: ${preset.config.bundler}`);
|
||||||
|
if (preset.config.includeFiles && preset.config.includeFiles.length > 0) {
|
||||||
|
console.log(` Include: ${preset.config.includeFiles.join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const confirmInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
confirmInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'action',
|
||||||
|
message: 'Use this configuration?',
|
||||||
|
choices: [
|
||||||
|
{ name: 'Yes, use as-is', value: 'use' },
|
||||||
|
{ name: 'Customize it', value: 'customize' },
|
||||||
|
],
|
||||||
|
default: 'use',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const confirmAnswers = await confirmInteract.runQueue();
|
||||||
|
const action = confirmAnswers.getAnswerFor('action') as string;
|
||||||
|
|
||||||
|
if (action === 'use') {
|
||||||
|
// Return the preset config directly
|
||||||
|
return { ...preset.config };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Customize: pre-fill with preset values
|
||||||
|
return this.configureManualBundle(preset.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure a bundle manually with optional pre-filled values
|
||||||
|
*/
|
||||||
|
private async configureManualBundle(
|
||||||
|
prefill?: Partial<interfaces.IBundleConfig>
|
||||||
|
): Promise<interfaces.IBundleConfig> {
|
||||||
|
const interact = new plugins.smartinteract.SmartInteract();
|
||||||
|
|
||||||
|
// Basic configuration questions
|
||||||
|
interact.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'from',
|
||||||
|
message: 'Entry point TypeScript file:',
|
||||||
|
default: prefill?.from || './ts_web/index.ts',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'to',
|
||||||
|
message: 'Output file path:',
|
||||||
|
default: prefill?.to || './dist_bundle/bundle.js',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'outputMode',
|
||||||
|
message: 'Output mode:',
|
||||||
|
choices: [
|
||||||
|
{ name: 'bundle - Standard JavaScript bundle file', value: 'bundle' },
|
||||||
|
{
|
||||||
|
name: 'base64ts - TypeScript file with base64-encoded content (for Deno compile)',
|
||||||
|
value: 'base64ts',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
default: prefill?.outputMode || 'bundle',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'list',
|
||||||
|
name: 'bundler',
|
||||||
|
message: 'Bundler to use:',
|
||||||
|
choices: [
|
||||||
|
{ name: 'esbuild (fastest, recommended)', value: 'esbuild' },
|
||||||
|
{ name: 'rolldown (Rust-based, Rollup compatible)', value: 'rolldown' },
|
||||||
|
{ name: 'rspack (Webpack compatible)', value: 'rspack' },
|
||||||
|
],
|
||||||
|
default: prefill?.bundler || 'esbuild',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'production',
|
||||||
|
message: 'Enable production mode (minification)?',
|
||||||
|
default: prefill?.production || false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'hasIncludeFiles',
|
||||||
|
message: 'Include additional files (HTML, assets)?',
|
||||||
|
default: prefill?.includeFiles && prefill.includeFiles.length > 0 ? true : false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const answers = await interact.runQueue();
|
||||||
|
|
||||||
|
const bundle: interfaces.IBundleConfig = {
|
||||||
|
from: answers.getAnswerFor('from'),
|
||||||
|
to: answers.getAnswerFor('to'),
|
||||||
|
outputMode: answers.getAnswerFor('outputMode') as interfaces.TOutputMode,
|
||||||
|
bundler: answers.getAnswerFor('bundler') as interfaces.TBundler,
|
||||||
|
production: answers.getAnswerFor('production'),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Update default output path based on mode
|
||||||
|
if (bundle.outputMode === 'base64ts' && bundle.to === './dist_bundle/bundle.js') {
|
||||||
|
const suggestInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
suggestInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'to',
|
||||||
|
message: 'For base64ts mode, suggest a .ts output path:',
|
||||||
|
default: './ts/embedded-bundle.ts',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const suggestAnswers = await suggestInteract.runQueue();
|
||||||
|
bundle.to = suggestAnswers.getAnswerFor('to');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle include files
|
||||||
|
if (answers.getAnswerFor('hasIncludeFiles')) {
|
||||||
|
bundle.includeFiles = await this.configureIncludeFiles(prefill?.includeFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure files to include
|
||||||
|
*/
|
||||||
|
private async configureIncludeFiles(prefill?: string[]): Promise<string[]> {
|
||||||
|
const includeFiles: string[] = [];
|
||||||
|
let addMore = true;
|
||||||
|
|
||||||
|
// If we have prefilled values, show them first
|
||||||
|
if (prefill && prefill.length > 0) {
|
||||||
|
console.log('\nPre-configured include patterns:');
|
||||||
|
prefill.forEach((p) => console.log(` - ${p}`));
|
||||||
|
|
||||||
|
const keepInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
keepInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'keepPrefill',
|
||||||
|
message: 'Keep these patterns?',
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const keepAnswers = await keepInteract.runQueue();
|
||||||
|
if (keepAnswers.getAnswerFor('keepPrefill')) {
|
||||||
|
includeFiles.push(...prefill);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\nAdd files or glob patterns to include (e.g., ./html/index.html, ./assets/**/*):\n');
|
||||||
|
|
||||||
|
// Ask if user wants to add more patterns
|
||||||
|
const addInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
addInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'addPatterns',
|
||||||
|
message: includeFiles.length > 0 ? 'Add more patterns?' : 'Add include patterns?',
|
||||||
|
default: includeFiles.length === 0,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const addAnswers = await addInteract.runQueue();
|
||||||
|
addMore = addAnswers.getAnswerFor('addPatterns');
|
||||||
|
|
||||||
|
while (addMore) {
|
||||||
|
const fileInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
fileInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'input',
|
||||||
|
name: 'pattern',
|
||||||
|
message: 'File or glob pattern:',
|
||||||
|
default: includeFiles.length === 0 ? './html/index.html' : '',
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const fileAnswers = await fileInteract.runQueue();
|
||||||
|
const pattern = fileAnswers.getAnswerFor('pattern');
|
||||||
|
|
||||||
|
if (pattern && pattern.trim()) {
|
||||||
|
includeFiles.push(pattern.trim());
|
||||||
|
console.log(` Added: ${pattern}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const continueInteract = new plugins.smartinteract.SmartInteract();
|
||||||
|
continueInteract.addQuestions([
|
||||||
|
{
|
||||||
|
type: 'confirm',
|
||||||
|
name: 'addMore',
|
||||||
|
message: 'Add another file/pattern?',
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const continueAnswers = await continueInteract.runQueue();
|
||||||
|
addMore = continueAnswers.getAnswerFor('addMore');
|
||||||
|
}
|
||||||
|
|
||||||
|
return includeFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the init command
|
||||||
|
*/
|
||||||
|
export async function runInit(): Promise<void> {
|
||||||
|
const handler = new InitHandler();
|
||||||
|
await handler.runWizard();
|
||||||
|
}
|
||||||
5
ts/mod_init/plugins.ts
Normal file
5
ts/mod_init/plugins.ts
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export * from '../plugins.js';
|
||||||
|
|
||||||
|
import * as smartinteract from '@push.rocks/smartinteract';
|
||||||
|
|
||||||
|
export { smartinteract };
|
||||||
113
ts/mod_output/index.ts
Normal file
113
ts/mod_output/index.ts
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import * as plugins from './plugins.js';
|
||||||
|
import * as paths from '../paths.js';
|
||||||
|
import * as interfaces from '../interfaces/index.js';
|
||||||
|
|
||||||
|
export class Base64TsOutput {
|
||||||
|
private files: interfaces.IBase64File[] = [];
|
||||||
|
private cwd: string;
|
||||||
|
|
||||||
|
constructor(cwd: string = paths.cwd) {
|
||||||
|
this.cwd = cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a file with its content to the output
|
||||||
|
*/
|
||||||
|
public addFile(filePath: string, content: Buffer | string): void {
|
||||||
|
const contentBuffer = typeof content === 'string' ? Buffer.from(content, 'utf-8') : content;
|
||||||
|
const contentBase64 = contentBuffer.toString('base64');
|
||||||
|
this.files.push({
|
||||||
|
path: filePath,
|
||||||
|
contentBase64,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add files matching a glob pattern
|
||||||
|
*/
|
||||||
|
public async addFilesFromGlob(pattern: string): Promise<void> {
|
||||||
|
const absolutePattern = plugins.smartpath.transform.toAbsolute(pattern, this.cwd) as string;
|
||||||
|
const patternDir = plugins.path.dirname(absolutePattern);
|
||||||
|
const patternBase = plugins.path.basename(absolutePattern);
|
||||||
|
|
||||||
|
// Check if it's a directory pattern or file pattern
|
||||||
|
const isGlobPattern = patternBase.includes('*');
|
||||||
|
|
||||||
|
if (isGlobPattern) {
|
||||||
|
// Handle glob patterns
|
||||||
|
const dirPath = patternDir.replace(/\/\*\*$/, '');
|
||||||
|
const dirExists = await plugins.fs.directory(dirPath).exists();
|
||||||
|
if (!dirExists) {
|
||||||
|
console.log(`Directory does not exist: ${dirPath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isRecursive = pattern.includes('**');
|
||||||
|
let entries;
|
||||||
|
if (isRecursive) {
|
||||||
|
entries = await plugins.fs.directory(dirPath).recursive().list();
|
||||||
|
} else {
|
||||||
|
entries = await plugins.fs.directory(dirPath).list();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter by pattern if needed
|
||||||
|
const filePattern = patternBase.replace('*', '.*');
|
||||||
|
const regex = new RegExp(filePattern);
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (!entry.isDirectory && regex.test(entry.name)) {
|
||||||
|
const fullPath = plugins.path.join(dirPath, entry.path);
|
||||||
|
const relativePath = plugins.path.relative(this.cwd, fullPath);
|
||||||
|
const content = await plugins.fs.file(fullPath).read();
|
||||||
|
this.addFile(relativePath, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle single file path
|
||||||
|
const fileExists = await plugins.fs.file(absolutePattern).exists();
|
||||||
|
if (!fileExists) {
|
||||||
|
console.log(`File does not exist: ${absolutePattern}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const relativePath = plugins.path.relative(this.cwd, absolutePattern);
|
||||||
|
const content = await plugins.fs.file(absolutePattern).read();
|
||||||
|
this.addFile(relativePath, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate TypeScript file content
|
||||||
|
*/
|
||||||
|
public generateTypeScript(): string {
|
||||||
|
const filesJson = JSON.stringify(this.files, null, 2);
|
||||||
|
return `// Auto-generated by tsbundle - do not edit
|
||||||
|
export const files: { path: string; contentBase64: string }[] = ${filesJson};
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the TypeScript file to disk
|
||||||
|
*/
|
||||||
|
public async writeToFile(outputPath: string): Promise<void> {
|
||||||
|
const absolutePath = plugins.smartpath.transform.toAbsolute(outputPath, this.cwd) as string;
|
||||||
|
const outputDir = plugins.path.dirname(absolutePath);
|
||||||
|
await plugins.fs.directory(outputDir).create();
|
||||||
|
const content = this.generateTypeScript();
|
||||||
|
await plugins.fs.file(absolutePath).encoding('utf8').write(content);
|
||||||
|
console.log(`Generated base64ts output: ${outputPath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all collected files
|
||||||
|
*/
|
||||||
|
public getFiles(): interfaces.IBase64File[] {
|
||||||
|
return this.files;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all collected files
|
||||||
|
*/
|
||||||
|
public clear(): void {
|
||||||
|
this.files = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
1
ts/mod_output/plugins.ts
Normal file
1
ts/mod_output/plugins.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from '../plugins.js';
|
||||||
@@ -11,10 +11,16 @@ export class TsBundleProcess {
|
|||||||
public async getAliases() {
|
public async getAliases() {
|
||||||
try {
|
try {
|
||||||
const aliasObject: Record<string, string> = {};
|
const aliasObject: Record<string, string> = {};
|
||||||
const localTsConfig = plugins.smartfile.fs.toObjectSync(
|
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
|
||||||
plugins.path.join(paths.cwd, 'tsconfig.json')
|
const tsconfigContent = await plugins.fs
|
||||||
);
|
.file(tsconfigPath)
|
||||||
if (localTsConfig.compilerOptions && localTsConfig.compilerOptions.paths) {
|
.encoding('utf8')
|
||||||
|
.read();
|
||||||
|
const localTsConfig = JSON.parse(tsconfigContent as string);
|
||||||
|
if (
|
||||||
|
localTsConfig.compilerOptions &&
|
||||||
|
localTsConfig.compilerOptions.paths
|
||||||
|
) {
|
||||||
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
||||||
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
||||||
aliasObject[alias] = aliasPath;
|
aliasObject[alias] = aliasPath;
|
||||||
@@ -66,9 +72,6 @@ export class TsBundleProcess {
|
|||||||
alias: await this.getAliases(),
|
alias: await this.getAliases(),
|
||||||
tsconfigFilename: paths.tsconfigPath,
|
tsconfigFilename: paths.tsconfigPath,
|
||||||
},
|
},
|
||||||
experimental: {
|
|
||||||
enableComposingJsPlugins: true,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const outputDir = plugins.path.dirname(toArg);
|
const outputDir = plugins.path.dirname(toArg);
|
||||||
@@ -88,7 +91,7 @@ export class TsBundleProcess {
|
|||||||
const run = async () => {
|
const run = async () => {
|
||||||
console.log('running spawned compilation process');
|
console.log('running spawned compilation process');
|
||||||
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
||||||
process.env.transportOptions
|
process.env.transportOptions,
|
||||||
);
|
);
|
||||||
console.log('=======> ROLLDOWN');
|
console.log('=======> ROLLDOWN');
|
||||||
console.log(transportOptions);
|
console.log(transportOptions);
|
||||||
@@ -98,16 +101,28 @@ const run = async () => {
|
|||||||
if (transportOptions.mode === 'test') {
|
if (transportOptions.mode === 'test') {
|
||||||
console.log('building for test:');
|
console.log('building for test:');
|
||||||
await tsbundleProcessInstance.buildTest(
|
await tsbundleProcessInstance.buildTest(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('building for production:');
|
console.log('building for production:');
|
||||||
await tsbundleProcessInstance.buildProduction(
|
await tsbundleProcessInstance.buildProduction(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ export * from '../plugins.js';
|
|||||||
|
|
||||||
import { rolldown } from 'rolldown';
|
import { rolldown } from 'rolldown';
|
||||||
|
|
||||||
export { rolldown }
|
export { rolldown };
|
||||||
|
|||||||
@@ -11,14 +11,23 @@ export class TsBundleProcess {
|
|||||||
public async getAliases() {
|
public async getAliases() {
|
||||||
try {
|
try {
|
||||||
const aliasObject: Record<string, string> = {};
|
const aliasObject: Record<string, string> = {};
|
||||||
const localTsConfig = plugins.smartfile.fs.toObjectSync(
|
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
|
||||||
plugins.path.join(paths.cwd, 'tsconfig.json')
|
const tsconfigContent = await plugins.fs
|
||||||
);
|
.file(tsconfigPath)
|
||||||
if (localTsConfig.compilerOptions && localTsConfig.compilerOptions.paths) {
|
.encoding('utf8')
|
||||||
|
.read();
|
||||||
|
const localTsConfig = JSON.parse(tsconfigContent as string);
|
||||||
|
if (
|
||||||
|
localTsConfig.compilerOptions &&
|
||||||
|
localTsConfig.compilerOptions.paths
|
||||||
|
) {
|
||||||
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
for (const alias of Object.keys(localTsConfig.compilerOptions.paths)) {
|
||||||
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
|
||||||
// Convert TypeScript path to absolute path for rspack
|
// Convert TypeScript path to absolute path for rspack
|
||||||
aliasObject[alias.replace('/*', '')] = plugins.path.resolve(paths.cwd, aliasPath.replace('/*', ''));
|
aliasObject[alias.replace('/*', '')] = plugins.path.resolve(
|
||||||
|
paths.cwd,
|
||||||
|
aliasPath.replace('/*', ''),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return aliasObject;
|
return aliasObject;
|
||||||
@@ -96,13 +105,15 @@ export class TsBundleProcess {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(stats.toString({
|
console.log(
|
||||||
|
stats.toString({
|
||||||
colors: true,
|
colors: true,
|
||||||
modules: false,
|
modules: false,
|
||||||
children: false,
|
children: false,
|
||||||
chunks: false,
|
chunks: false,
|
||||||
chunkModules: false,
|
chunkModules: false,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
});
|
});
|
||||||
@@ -192,13 +203,15 @@ export class TsBundleProcess {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(stats.toString({
|
console.log(
|
||||||
|
stats.toString({
|
||||||
colors: true,
|
colors: true,
|
||||||
modules: false,
|
modules: false,
|
||||||
children: false,
|
children: false,
|
||||||
chunks: false,
|
chunks: false,
|
||||||
chunkModules: false,
|
chunkModules: false,
|
||||||
}));
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
});
|
});
|
||||||
@@ -209,7 +222,7 @@ export class TsBundleProcess {
|
|||||||
const run = async () => {
|
const run = async () => {
|
||||||
console.log('running spawned compilation process');
|
console.log('running spawned compilation process');
|
||||||
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
|
||||||
process.env.transportOptions
|
process.env.transportOptions,
|
||||||
);
|
);
|
||||||
console.log('=======> RSPACK');
|
console.log('=======> RSPACK');
|
||||||
console.log(transportOptions);
|
console.log(transportOptions);
|
||||||
@@ -219,16 +232,28 @@ const run = async () => {
|
|||||||
if (transportOptions.mode === 'test') {
|
if (transportOptions.mode === 'test') {
|
||||||
console.log('building for test:');
|
console.log('building for test:');
|
||||||
await tsbundleProcessInstance.buildTest(
|
await tsbundleProcessInstance.buildTest(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('building for production:');
|
console.log('building for production:');
|
||||||
await tsbundleProcessInstance.buildProduction(
|
await tsbundleProcessInstance.buildProduction(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
|
transportOptions.from,
|
||||||
transportOptions.argv
|
process.cwd(),
|
||||||
|
),
|
||||||
|
plugins.smartpath.transform.makeAbsolute(
|
||||||
|
transportOptions.to,
|
||||||
|
process.cwd(),
|
||||||
|
),
|
||||||
|
transportOptions.argv,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,4 +2,4 @@ export * from '../plugins.js';
|
|||||||
|
|
||||||
import { rspack } from '@rspack/core';
|
import { rspack } from '@rspack/core';
|
||||||
|
|
||||||
export { rspack }
|
export { rspack };
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as plugins from './plugins.js';
|
|||||||
export const cwd = process.cwd();
|
export const cwd = process.cwd();
|
||||||
export const packageDir = plugins.path.join(
|
export const packageDir = plugins.path.join(
|
||||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||||
'../'
|
'../',
|
||||||
);
|
);
|
||||||
export const htmlDir = plugins.path.join(cwd, './html');
|
export const htmlDir = plugins.path.join(cwd, './html');
|
||||||
export const distServeDir = plugins.path.join(cwd, './dist_serve');
|
export const distServeDir = plugins.path.join(cwd, './dist_serve');
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import * as path from 'path';
|
|||||||
export { path };
|
export { path };
|
||||||
|
|
||||||
// pushrocks scope
|
// pushrocks scope
|
||||||
|
import * as npmextra from '@push.rocks/npmextra';
|
||||||
import * as smartcli from '@push.rocks/smartcli';
|
import * as smartcli from '@push.rocks/smartcli';
|
||||||
import * as smartfile from '@push.rocks/smartfile';
|
import * as smartfs from '@push.rocks/smartfs';
|
||||||
|
import * as smartinteract from '@push.rocks/smartinteract';
|
||||||
import * as smartlog from '@push.rocks/smartlog';
|
import * as smartlog from '@push.rocks/smartlog';
|
||||||
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
|
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
|
||||||
import * as smartpath from '@push.rocks/smartpath';
|
import * as smartpath from '@push.rocks/smartpath';
|
||||||
@@ -13,11 +15,16 @@ import * as smartpromise from '@push.rocks/smartpromise';
|
|||||||
import * as smartspawn from '@push.rocks/smartspawn';
|
import * as smartspawn from '@push.rocks/smartspawn';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
npmextra,
|
||||||
smartcli,
|
smartcli,
|
||||||
smartfile,
|
smartfs,
|
||||||
|
smartinteract,
|
||||||
smartlog,
|
smartlog,
|
||||||
smartlogDestinationLocal,
|
smartlogDestinationLocal,
|
||||||
smartpath,
|
smartpath,
|
||||||
smartpromise,
|
smartpromise,
|
||||||
smartspawn,
|
smartspawn,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Create a shared SmartFs instance using Node provider
|
||||||
|
export const fs = new smartfs.SmartFs(new smartfs.SmartFsProviderNode());
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import * as interfaces from './interfaces/index.js';
|
|||||||
import { logger } from './tsbundle.logging.js';
|
import { logger } from './tsbundle.logging.js';
|
||||||
|
|
||||||
export class TsBundle {
|
export class TsBundle {
|
||||||
|
|
||||||
public async build(
|
public async build(
|
||||||
cwdArg: string,
|
cwdArg: string,
|
||||||
fromArg: string = './ts_web/index.ts',
|
fromArg: string = './ts_web/index.ts',
|
||||||
toArg: string = './dist_bundle/bundle.js',
|
toArg: string = './dist_bundle/bundle.js',
|
||||||
argvArg: interfaces.ICliOptions
|
argvArg: interfaces.ICliOptions,
|
||||||
) {
|
) {
|
||||||
const done = plugins.smartpromise.defer();
|
const done = plugins.smartpromise.defer();
|
||||||
const getBundlerPath = () => {
|
const getBundlerPath = () => {
|
||||||
@@ -21,20 +20,20 @@ export class TsBundle {
|
|||||||
default:
|
default:
|
||||||
return './mod_esbuild/index.child.js';
|
return './mod_esbuild/index.child.js';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
const transportOptions: interfaces.IEnvTransportOptions = {
|
const transportOptions: interfaces.IEnvTransportOptions = {
|
||||||
cwd: cwdArg,
|
cwd: cwdArg,
|
||||||
from: fromArg,
|
from: fromArg,
|
||||||
to: toArg,
|
to: toArg,
|
||||||
mode: argvArg && argvArg.production ? 'production' : 'test',
|
mode: argvArg && argvArg.production ? 'production' : 'test',
|
||||||
argv: {
|
argv: {
|
||||||
...argvArg
|
...argvArg,
|
||||||
}
|
},
|
||||||
}
|
};
|
||||||
const threadsimple = new plugins.smartspawn.ThreadSimple(
|
const threadsimple = new plugins.smartspawn.ThreadSimple(
|
||||||
plugins.path.join(
|
plugins.path.join(
|
||||||
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
|
||||||
getBundlerPath()
|
getBundlerPath(),
|
||||||
),
|
),
|
||||||
[],
|
[],
|
||||||
{
|
{
|
||||||
@@ -42,7 +41,7 @@ export class TsBundle {
|
|||||||
...process.env,
|
...process.env,
|
||||||
transportOptions: JSON.stringify(transportOptions),
|
transportOptions: JSON.stringify(transportOptions),
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const childProcess = await threadsimple.start();
|
const childProcess = await threadsimple.start();
|
||||||
childProcess.on('exit', (status) => {
|
childProcess.on('exit', (status) => {
|
||||||
|
|||||||
@@ -1,61 +1,23 @@
|
|||||||
import * as plugins from './plugins.js';
|
import * as plugins from './plugins.js';
|
||||||
import { TsBundle } from './tsbundle.class.tsbundle.js';
|
import { runCustomBundles } from './mod_custom/index.js';
|
||||||
import { HtmlHandler } from './mod_html/index.js';
|
import { runInit } from './mod_init/index.js';
|
||||||
import { logger } from './tsbundle.logging.js';
|
|
||||||
import { AssetsHandler } from './mod_assets/index.js';
|
|
||||||
|
|
||||||
export const runCli = async () => {
|
export const runCli = async () => {
|
||||||
const tsBundleCli = new plugins.smartcli.Smartcli();
|
const tsBundleCli = new plugins.smartcli.Smartcli();
|
||||||
|
|
||||||
|
// Default command: run custom bundles from npmextra.json
|
||||||
tsBundleCli.standardCommand().subscribe(async (argvArg) => {
|
tsBundleCli.standardCommand().subscribe(async (argvArg) => {
|
||||||
const tsbundle = new TsBundle();
|
await runCustomBundles();
|
||||||
await tsbundle.build(process.cwd(), argvArg.from, argvArg.to, argvArg);
|
|
||||||
return;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tsBundleCli.addCommand('element').subscribe(async (argvArg) => {
|
// Explicit custom command (same as default)
|
||||||
const tsbundle = new TsBundle();
|
tsBundleCli.addCommand('custom').subscribe(async (argvArg) => {
|
||||||
await tsbundle.build(
|
await runCustomBundles();
|
||||||
process.cwd(),
|
|
||||||
'./ts_web/index.ts',
|
|
||||||
'./dist_bundle/bundle.js',
|
|
||||||
argvArg
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tsBundleCli.addCommand('npm').subscribe(async (argvArg) => {
|
// Interactive init wizard
|
||||||
const tsbundle = new TsBundle();
|
tsBundleCli.addCommand('init').subscribe(async (argvArg) => {
|
||||||
const htmlHandler = new HtmlHandler();
|
await runInit();
|
||||||
await tsbundle.build(
|
|
||||||
process.cwd(),
|
|
||||||
'./ts/index.ts',
|
|
||||||
'./dist_bundle/bundle.js',
|
|
||||||
argvArg
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
tsBundleCli.addCommand('website').subscribe(async (argvArg) => {
|
|
||||||
const tsbundle = new TsBundle();
|
|
||||||
|
|
||||||
// lets deal with the html
|
|
||||||
const htmlHandler = new HtmlHandler();
|
|
||||||
await tsbundle.build(
|
|
||||||
process.cwd(),
|
|
||||||
'./ts_web/index.ts',
|
|
||||||
'./dist_serve/bundle.js',
|
|
||||||
argvArg
|
|
||||||
);
|
|
||||||
const htmlFiles = await plugins.smartfile.fs.listFiles('./html', /\.html/);
|
|
||||||
for (const htmlFile of htmlFiles) {
|
|
||||||
await htmlHandler.processHtml({
|
|
||||||
from: `./html/${htmlFile}`,
|
|
||||||
to: `./dist_serve/${htmlFile}`,
|
|
||||||
minify: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// lets deal with the assets
|
|
||||||
const assetsHandler = new AssetsHandler();
|
|
||||||
await assetsHandler.processAssets();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
tsBundleCli.startParse();
|
tsBundleCli.startParse();
|
||||||
|
|||||||
@@ -12,4 +12,6 @@ export const logger = new plugins.smartlog.Smartlog({
|
|||||||
minimumLogLevel: 'silly',
|
minimumLogLevel: 'silly',
|
||||||
});
|
});
|
||||||
|
|
||||||
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());
|
logger.addLogDestination(
|
||||||
|
new plugins.smartlogDestinationLocal.DestinationLocal(),
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
|
||||||
"useDefineForClassFields": false,
|
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "NodeNext",
|
"module": "NodeNext",
|
||||||
"moduleResolution": "NodeNext",
|
"moduleResolution": "NodeNext",
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"verbatimModuleSyntax": true
|
"verbatimModuleSyntax": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {}
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["dist_*/**/*.d.ts"]
|
||||||
"dist_*/**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user