Compare commits

..

73 Commits

Author SHA1 Message Date
6dd7d6e093 v2.6.0
Some checks failed
Default (tags) / security (push) Successful in 44s
Default (tags) / test (push) Failing after 37s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-11-23 13:12:17 +00:00
cd53bdb6f4 feat(core): Integrate Rolldown as optional bundler, migrate filesystem to smartfs, and update bundler/tooling 2025-11-23 13:12:17 +00:00
1bb05bfd2e v2.5.2 2025-11-17 08:09:37 +00:00
94aff06cbc fix(tsconfig): Update TypeScript configs to ES2022 and remove deprecated compiler flags 2025-11-17 08:09:37 +00:00
b69abda86c 2.5.1 2025-06-26 20:09:58 +00:00
82c7bb3ee1 fix(readme): Update license and legal information section in readme 2025-06-26 20:09:58 +00:00
6c7c3aaa88 2.5.0 2025-06-26 20:07:27 +00:00
01b3128bcc feat(documentation): Improve README with comprehensive installation, usage, and API reference details 2025-06-26 20:07:27 +00:00
08da97c018 2.4.1 2025-06-26 19:58:46 +00:00
40d6b8c40d fix(tests): Improve decorator tests and add LitElement component tests for better validation 2025-06-26 19:58:45 +00:00
bbe96ea1f5 2.4.0 2025-06-19 20:37:21 +00:00
a4b6956072 feat(bundler): Introduce rspack bundler support and update multi-bundler workflow 2025-06-19 20:37:21 +00:00
2bc219e3bc 2.3.0 2025-06-19 20:10:45 +00:00
2a808cc186 feat(bundler): Integrate rolldown bundler support and update bundler selection logic 2025-06-19 20:10:45 +00:00
09a470d409 2.2.8 2025-06-19 13:47:24 +00:00
c0f23deab8 fix(ts_bundle): Disable splitting and tree shaking in build configurations 2025-06-19 13:47:23 +00:00
e92758586f 2.2.7 2025-06-19 13:15:47 +00:00
8603206c85 2.2.6 2025-06-19 13:15:23 +00:00
60bcfd501f Refactor code structure for improved readability and maintainability 2025-06-19 13:15:06 +00:00
b01b7d23df 2.2.5 2025-01-29 18:33:30 +01:00
45c4472c53 fix(mod_assets): Fix async handling in asset processing 2025-01-29 18:33:29 +01:00
337bee3272 2.2.4 2025-01-29 18:27:14 +01:00
709a67fe82 fix(mod_assets): Fix logging message in ensureAssetsDir to correctly state when directory is created 2025-01-29 18:27:13 +01:00
37082bd8f4 2.2.3 2025-01-29 18:25:06 +01:00
2c8623ab58 fix(mod_assets): Fix issue with asset directory copy 2025-01-29 18:25:05 +01:00
126fb5449b 2.2.2 2025-01-29 18:15:00 +01:00
8a0095f90a fix(dependencies): Update smartfile dependency and fix spacing issue in assets module 2025-01-29 18:14:59 +01:00
704a3d1948 2.2.1 2025-01-29 13:18:04 +01:00
0538ed44af fix(index): Export mod_assets for programmatic use 2025-01-29 13:18:04 +01:00
3fa8b0ca3b 2.2.0 2025-01-29 13:12:01 +01:00
10af586f28 feat(AssetsHandler): Add asset handling to the CLI workflow 2025-01-29 13:12:01 +01:00
230e217368 2.1.1 2025-01-28 12:11:40 +01:00
f5d6ec81ff fix(core): Update dependencies and remove GitLab CI configuration. 2025-01-28 12:11:40 +01:00
56f32136c5 2.1.0 2024-10-27 18:36:36 +01:00
84854b0b40 feat(mod_esbuild): Add alias support to esbuild bundling process 2024-10-27 18:36:36 +01:00
32b0781d72 2.0.15 2024-01-10 05:07:09 +01:00
e47ba642f2 fix(core): update 2024-01-10 05:07:08 +01:00
49ecf9d4ca 2.0.14 2024-01-09 16:54:30 +01:00
7bd0032007 fix(core): update 2024-01-09 16:54:29 +01:00
866c203856 2.0.13 2024-01-08 16:48:12 +01:00
3e673bca6b fix(core): update 2024-01-08 16:48:11 +01:00
5c3dfe0920 2.0.12 2024-01-08 16:28:23 +01:00
c08a9065a1 fix(core): update 2024-01-08 16:28:22 +01:00
f4071f0b64 2.0.11 2024-01-08 16:24:52 +01:00
335cc19211 fix(core): update 2024-01-08 16:24:52 +01:00
25851c2b64 2.0.10 2023-10-03 19:12:49 +02:00
73a6ce2786 fix(core): update 2023-10-03 19:12:49 +02:00
8bd279637b 2.0.9 2023-08-26 15:08:23 +02:00
1e37857c26 fix(core): update 2023-08-26 15:08:23 +02:00
93a1052bf5 2.0.8 2023-06-03 17:33:32 +02:00
6e6452df61 fix(core): update 2023-06-03 17:33:32 +02:00
3de5a91885 2.0.7 2022-08-03 19:43:18 +02:00
f7ca1b2135 fix(core): update 2022-08-03 19:43:18 +02:00
3076e13179 2.0.6 2022-07-24 15:51:55 +02:00
f3b50d384a fix(core): update 2022-07-24 15:51:55 +02:00
6dcb3f7c2a 2.0.5 2022-06-02 01:00:49 +02:00
daba025307 fix(core): update 2022-06-02 01:00:49 +02:00
00383171ff 2.0.4 2022-05-25 11:56:11 +02:00
2ce9b08911 fix(core): update 2022-05-25 11:56:10 +02:00
d603baf65e 2.0.3 2022-05-04 18:51:15 +02:00
50e4909984 fix(core): update 2022-05-04 18:51:15 +02:00
7208274156 2.0.2 2022-05-04 17:39:00 +02:00
41ec42d068 fix(core): update 2022-05-04 17:39:00 +02:00
d159b9a6a8 2.0.1 2022-05-04 17:20:28 +02:00
45d0d74559 fix(core): update 2022-05-04 17:20:28 +02:00
661fdf75cf 2.0.0 2022-05-04 17:14:39 +02:00
6f17a76b6e BREAKING CHANGE(core): remove parcel and rollup 2022-05-04 17:14:38 +02:00
324ef71b6f 1.0.104 2022-05-04 17:13:52 +02:00
58a7dca142 fix(core): update 2022-05-04 17:13:52 +02:00
e243e17acb 1.0.103 2022-05-02 18:23:37 +02:00
d788bdc78b fix(core): update 2022-05-02 18:23:36 +02:00
3ef8a145a5 1.0.102 2022-03-25 19:48:58 +01:00
3377554969 fix(core): update 2022-03-25 19:48:58 +01:00
43 changed files with 10041 additions and 18710 deletions

View 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

View 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
View File

@@ -3,7 +3,6 @@
# artifacts
coverage/
public/
pages/
# installs
node_modules/
@@ -17,4 +16,8 @@ node_modules/
dist/
dist_*/
# custom
# AI
.claude/
.serena/
#------# custom

View File

@@ -1,141 +0,0 @@
# gitzone ci_default
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache:
paths:
- .npmci_cache/
key: '$CI_BUILD_STAGE'
stages:
- security
- test
- release
- metadata
before_script:
- npm install -g @shipzone/npmci
# ====================
# security stage
# ====================
mirror:
stage: security
script:
- npmci git mirror
only:
- tags
tags:
- lossless
- docker
- notpriv
auditProductionDependencies:
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
stage: security
script:
- npmci npm prepare
- npmci command npm install --production --ignore-scripts
- npmci command npm config set registry https://registry.npmjs.org
- npmci command npm audit --audit-level=high --only=prod --production
tags:
- docker
allow_failure: true
auditDevDependencies:
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
stage: security
script:
- npmci npm prepare
- npmci command npm install --ignore-scripts
- npmci command npm config set registry https://registry.npmjs.org
- npmci command npm audit --audit-level=high --only=dev
tags:
- docker
allow_failure: true
# ====================
# test stage
# ====================
testStable:
stage: test
script:
- npmci npm prepare
- npmci node install stable
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
testBuild:
stage: test
script:
- npmci npm prepare
- npmci node install stable
- npmci npm install
- npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
release:
stage: release
script:
- npmci node install stable
- npmci npm publish
only:
- tags
tags:
- lossless
- docker
- notpriv
# ====================
# metadata stage
# ====================
codequality:
stage: metadata
allow_failure: true
only:
- tags
script:
- npmci command npm install -g tslint typescript
- npmci npm prepare
- npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags:
- lossless
- docker
- priv
trigger:
stage: metadata
script:
- npmci trigger
only:
- tags
tags:
- lossless
- docker
- notpriv
pages:
stage: metadata
script:
- npmci node install lts
- npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare
- npmci npm install
- npmci command tsdoc
tags:
- lossless
- docker
- notpriv
only:
- tags
artifacts:
expire_in: 1 week
paths:
- public
allow_failure: true

9
assets/tsconfig.json Normal file
View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ES2022",
"moduleResolution": "node12",
"preserveValueImports": true,
"esModuleInterop": true
}
}

139
changelog.md Normal file
View File

@@ -0,0 +1,139 @@
# Changelog
## 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)
Update license and legal information section in readme
- Replaced contribution guidelines with detailed legal and trademark information
- Clarified MIT license usage and limitations regarding trade names and trademarks
- Added company information for Task Venture Capital GmbH
## 2025-06-26 - 2.5.0 - feat(documentation)
Improve README with comprehensive installation, usage, and API reference details
- Updated installation instructions for both global and local setups
- Added a quick start guide featuring CLI usage and API examples
- Enhanced sections for available bundlers and specialized CLI commands
- Expanded API reference with detailed examples for TsBundle, HtmlHandler, and AssetsHandler
- Reorganized content to improve clarity and best practices guidance
## 2025-06-26 - 2.4.1 - fix(tests)
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
- Added test-lit.ts to ensure LitElement component renders correctly and increments counter on click
## 2025-06-19 - 2.4.0 - feat(bundler)
Introduce rspack bundler support and update multi-bundler workflow
- Added full support for rspack with its own implementation in ts/mod_rspack
- Updated package.json: new dependency on @rspack/core and revised description
- Refactored bundler types and switch statement to remove deprecated rollup and parcel options
- Modified test suite to include tests for esbuild, rolldown, and rspack with bundle size comparisons
- Adjusted output configuration for esbuild and rolldown for dynamic naming and inline dynamic imports
## 2025-06-19 - 2.3.0 - feat(bundler)
Integrate rolldown bundler support and update bundler selection logic
- Added rolldown dependency to package.json
- Extended ICliOptions to include 'rolldown' as a valid bundler option
- Created ts/mod_rolldown module with buildTest and buildProduction implementations
- Updated getBundlerPath in tsbundle.class.tsbundle.ts to route to new rolldown module
- Revised readme and hints documentation for rolldown usage
## 2025-01-29 - 2.2.5 - fix(mod_assets)
Fix async handling in asset processing
- Ensured that the empty directory operation is awaited in the asset processing workflow.
## 2025-01-29 - 2.2.4 - fix(mod_assets)
Fix logging message in ensureAssetsDir to correctly state when directory is created
- Corrected logging output in ensureAssetsDir method to indicate directory creation.
## 2025-01-29 - 2.2.3 - fix(mod_assets)
Fix issue with asset directory copy
- Updated dependency '@push.rocks/smartfile' to version '^11.2.0'
- Ensure target directory is properly replaced when copying assets
## 2025-01-29 - 2.2.2 - fix(dependencies)
Update smartfile dependency and fix spacing issue in assets module
- Updated @push.rocks/smartfile from ^11.1.6 to ^11.1.8
- Fixed a spacing issue in the processAssets function within the assets module
## 2025-01-29 - 2.2.1 - fix(index)
Export mod_assets for programmatic use
- Added export for mod_assets/index in ts/index.ts to make it usable programmatically.
## 2025-01-29 - 2.2.0 - feat(AssetsHandler)
Add asset handling to the CLI workflow
- Introduced AssetsHandler class for managing asset directories and files.
- Updated tsbundle.cli.ts to include asset processing in the 'website' command.
## 2025-01-28 - 2.1.1 - fix(core)
Update dependencies and remove GitLab CI configuration.
- Updated several devDependencies to newer versions for improved stability and performance.
- Updated core dependencies including esbuild and TypeScript.
- Removed the .gitlab-ci.yml file, which could suggest a change in continuous integration setup.
## 2024-10-27 - 2.1.0 - feat(mod_esbuild)
Add alias support to esbuild bundling process
- Updated dependencies in package.json to latest versions.
- 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
Released version 2.0.0 with breaking changes and subsequent fixes.
- BREAKING CHANGE(core): Removed parcel and rollup
- fix(core): Addressed initial issues in new major version
## 2023-10-03 - 2.0.10 - Fix Updates
Ongoing updates and improvements.
- fix(core): General updates and enhancements
## 2024-01-10 - 2.0.11-2.0.15 - Minor Fixes
Cumulative fixes and updates from recent releases.
- fix(core): Continuous improvement cycle across versions

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env node
process.env.CLI_CALL = 'true';
import * as tsrun from '@gitzone/tsrun';
import * as tsrun from '@git.zone/tsrun';
tsrun.runPath('./cli.child.js', import.meta.url);

View File

@@ -6,7 +6,7 @@
"gitscope": "gitzone",
"gitrepo": "tsbundle",
"description": "a bundler using rollup for painless bundling of web projects",
"npmPackagename": "@gitzone/tsbundle",
"npmPackagename": "@git.zone/tsbundle",
"license": "MIT",
"projectDomain": "git.zone"
}
@@ -15,4 +15,4 @@
"npmGlobalTools": [],
"npmAccessLevel": "public"
}
}
}

18045
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,57 +1,43 @@
{
"name": "@gitzone/tsbundle",
"version": "1.0.101",
"name": "@git.zone/tsbundle",
"version": "2.6.0",
"private": false,
"description": "a bundler using rollup 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",
"typings": "dist_ts/index.d.ts",
"type": "module",
"author": "Lossless GmbH",
"license": "MIT",
"scripts": {
"test": "npm run build && (tstest test/) && (cd test && node ../cli.js --production)",
"build": "(tsbuild --web --allowimplicitany)"
"test": "npm run build && (tstest test/ --verbose)",
"build": "(tsbuild --web --allowimplicitany)",
"buildDocs": "tsdoc"
},
"bin": {
"tsbundle": "cli.js"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.1.59",
"@gitzone/tsrun": "^1.2.31",
"@gitzone/tstest": "^1.0.69",
"@pushrocks/tapbundle": "^5.0.2",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.15.0"
"@git.zone/tsbuild": "^3.1.0",
"@git.zone/tsrun": "^2.0.0",
"@git.zone/tstest": "^3.1.3",
"@types/node": "^22.12.0"
},
"dependencies": {
"@babel/core": "^7.17.7",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-decorators": "^7.17.2",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/runtime": "^7.17.7",
"@pushrocks/early": "^3.0.6",
"@pushrocks/smartcli": "^3.0.14",
"@pushrocks/smartfile": "^9.0.6",
"@pushrocks/smartlog": "^2.0.44",
"@pushrocks/smartlog-destination-local": "^8.0.8",
"@pushrocks/smartparcel": "^1.0.13",
"@pushrocks/smartpath": "^5.0.5",
"@pushrocks/smartpromise": "^3.1.7",
"@pushrocks/smartspawn": "^2.0.9",
"@rollup/plugin-commonjs": "^21.0.2",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.1.3",
"@rollup/plugin-typescript": "^8.3.1",
"@types/html-minifier": "^4.0.2",
"@types/node": "^17.0.21",
"esbuild": "^0.14.27",
"@push.rocks/early": "^4.0.4",
"@push.rocks/smartcli": "^4.0.19",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfs": "^1.1.0",
"@push.rocks/smartlog": "^3.1.8",
"@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartpath": "^6.0.0",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartspawn": "^3.0.3",
"@rspack/core": "^1.6.4",
"@types/html-minifier": "^4.0.6",
"esbuild": "^0.27.0",
"html-minifier": "^4.0.0",
"rollup": "^2.70.1",
"rollup-plugin-babel": "^4.4.0",
"rollup-plugin-sourcemaps": "^0.6.3",
"rollup-plugin-terser": "^7.0.2",
"typescript": "4.7.0"
"rolldown": "1.0.0-beta.51",
"typescript": "5.9.3"
},
"files": [
"ts/**/*",
@@ -67,5 +53,17 @@
],
"browserslist": [
"last 1 chrome versions"
]
],
"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": {}
}
}

8316
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

65
readme.hints.md Normal file
View File

@@ -0,0 +1,65 @@
# 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
- tsbundle uses a child process architecture where each bundler runs in a separate process
- Configuration is passed via environment variables as JSON (IEnvTransportOptions)
- The main class `TsBundle` spawns child processes using `smartspawn.ThreadSimple`
## Bundler Implementations
- **esbuild** (default): Fully implemented, production ready, 3.9K 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)
- **parcel**: Removed (was never implemented)
## Adding New Bundlers
To add a new bundler, you need:
1. Update `ICliOptions` interface to include the bundler name
2. Add case in `getBundlerPath()` switch statement
3. Create `mod_<bundler>/` directory with:
- `plugins.ts`: Import and re-export the bundler
- `index.child.ts`: Implement TsBundleProcess class with buildTest() and buildProduction()
4. Add bundler to package.json dependencies
## Rolldown Specific Notes
- Rolldown is in beta (v1.0.0-beta.18) but working well
- API: Use `rolldown()` function directly, not `rolldown.rolldown()`
- Output options go in the `write()` method, not the initial config
- Uses `dir` and `entryFileNames` instead of `file` for output (handles dynamic imports)
- Includes `inlineDynamicImports: true` to avoid chunk splitting issues
- Produces smaller minified bundles than esbuild (1.5K vs 2.2K in tests)
- Supports TypeScript via `resolve.tsconfigFilename`
## Rspack Specific Notes
- Rspack v1.3.15 - stable and production ready
- Uses webpack-compatible API (callback-based)
- Built-in SWC loader for TypeScript transpilation
- Produces larger bundles than esbuild/rolldown due to webpack runtime overhead
- Best choice if you need webpack compatibility or advanced features
- Supports ES modules output via `experiments.outputModule: true`
## CLI Usage
- Default bundler: `tsbundle` (uses esbuild)
- Specify bundler: `tsbundle --bundler=rolldown` or `tsbundle --bundler=rspack`
- Production mode: `tsbundle --production`
- Combined: `tsbundle --bundler=rolldown --production`
## Known 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

350
readme.md
View File

@@ -1,78 +1,310 @@
# @gitzone/tsbundle
a bundler using rollup for painless bundling of web projects
# @git.zone/tsbundle
## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@gitzone/tsbundle)
* [gitlab.com (source)](https://gitlab.com/gitzone/tsbundle)
* [github.com (source mirror)](https://github.com/gitzone/tsbundle)
* [docs (typedoc)](https://gitzone.gitlab.io/tsbundle/)
A powerful multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects.
## Status for master
## Issue Reporting and Security
Status Category | Status Badge
-- | --
GitLab Pipelines | [![pipeline status](https://gitlab.com/gitzone/tsbundle/badges/master/pipeline.svg)](https://lossless.cloud)
GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/gitzone/tsbundle/badges/master/coverage.svg)](https://lossless.cloud)
npm | [![npm downloads per month](https://badgen.net/npm/dy/@gitzone/tsbundle)](https://lossless.cloud)
Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/gitzone/tsbundle)](https://lossless.cloud)
TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@gitzone/tsbundle)](https://lossless.cloud)
PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@gitzone/tsbundle)](https://lossless.cloud)
BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@gitzone/tsbundle)](https://lossless.cloud)
Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20Windows%2010/yes/green?icon=windows)](https://lossless.cloud) [![Supports Mac OS X](https://badgen.net/badge/supports%20Mac%20OS%20X/yes/green?icon=apple)](https://lossless.cloud)
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.
## Usage
## Installation
Use TypeScript for best in class intellisense.
```bash
# Global installation for CLI usage
npm install -g @git.zone/tsbundle
tsbundle will bundle modern JavaScript websites in an Google Bot conformant way so things like AdSense do work.
tsbundle supports two modes of usage: CLI and API usage.
### CLI
```shell
# Note: This is code that belongs into your terminal ;)
# Install the tool for cli usage
# Globally
npm install -g @gitzone/tsbundle
# Locally for use in your pacakge.json
npm install --save-dev @gitzone/tsbundle
# then use it
tsbundle --from="./ts/index.ts" --to="dist/bundle.js"
## note you can call tsbundle without arguments. Default values are --from="./ts_web/index.ts" --to="dist_bundle/bundle.js"
## You can use --production to enable minification using terser
# Local installation for project usage
npm install --save-dev @git.zone/tsbundle
```
## API
## Quick Start
You are using TypeScript, aren't you? Most of the stuff is apparent from the IDE intellisense.
### CLI Usage
The simplest way to bundle your project:
```bash
# Bundle with default settings (from ./ts_web/index.ts to ./dist_bundle/bundle.js)
tsbundle
# Bundle with custom paths
tsbundle --from="./src/index.ts" --to="./dist/bundle.js"
# Production build with minification
tsbundle --from="./src/index.ts" --to="./dist/bundle.js" --production
# Use a specific bundler
tsbundle --bundler=rolldown
```
### API Usage
```typescript
import { TsBundle } from '@gitozne/tsbundle';
import { TsBundle } from '@git.zone/tsbundle';
const myTsBundleInstance = new TsBundle();
const bundler = new TsBundle();
const run = async () => {
await myTsBundleInstance.buildTest('./from/my.ts', './to/mybundle.js');
// OR
await myTsBundleInstance.buildProduction('./from/my.ts', './to/mybundle.js');
};
// Basic usage
await bundler.build(
process.cwd(), // working directory
'./src/index.ts', // entry point
'./dist/bundle.js', // output file
{ bundler: 'esbuild' }, // options
);
// Production build with rolldown
await bundler.build(process.cwd(), './src/index.ts', './dist/bundle.min.js', {
bundler: 'rolldown',
production: true,
});
```
## Contribution
## Available Bundlers
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
tsbundle supports three modern bundlers, each with its own strengths:
For further information read the linked docs at the top of this readme.
- **esbuild** (default): Extremely fast, great for development
- **rolldown**: Rust-based bundler with excellent tree-shaking
- **rspack**: High-performance bundler with webpack compatibility
> MIT licensed | **&copy;** [Lossless GmbH](https://lossless.gmbh)
| By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
Select your bundler using the `--bundler` flag in CLI or the `bundler` option in API.
[![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com)
## CLI Commands
### Default Command
Bundle TypeScript/JavaScript projects:
```bash
tsbundle [options]
Options:
--from Source entry point (default: ./ts_web/index.ts)
--to Output bundle path (default: ./dist_bundle/bundle.js)
--production Enable production mode with minification
--bundler Choose bundler: esbuild, rolldown, or rspack
--commonjs Output CommonJS format instead of ESM
--skiplibcheck Skip TypeScript library checking
```
### Specialized Commands
#### `tsbundle element`
Bundle web components with standard naming conventions:
```bash
tsbundle element
# Bundles from ./ts_web/elements/<elementName>.ts to ./dist_bundle/bundle.js
```
#### `tsbundle npm`
Bundle npm packages for distribution:
```bash
tsbundle npm
# Prepares your package for npm publishing
```
#### `tsbundle website`
Full website bundling with HTML processing and asset handling:
```bash
tsbundle website
# Bundles JavaScript, processes HTML, and copies assets
```
## API Reference
### TsBundle Class
The main bundler class for programmatic usage.
```typescript
import { TsBundle } from '@git.zone/tsbundle';
const bundler = new TsBundle();
// Method signature
await bundler.build(
cwdArg: string, // Working directory
fromArg?: string, // Entry point (default: './ts_web/index.ts')
toArg?: string, // Output path (default: './dist_bundle/bundle.js')
argvArg?: ICliOptions // Configuration options
): Promise<void>
```
#### ICliOptions Interface
```typescript
interface ICliOptions {
bundler: 'esbuild' | 'rolldown' | 'rspack'; // Bundler to use
production?: boolean; // Enable production optimizations
commonjs?: boolean; // Output CommonJS format
skiplibcheck?: boolean; // Skip TypeScript lib checking
}
```
### HtmlHandler Class
Process and minify HTML files:
```typescript
import { HtmlHandler } from '@git.zone/tsbundle';
const htmlHandler = new HtmlHandler();
// Check if HTML files exist
const exists = await htmlHandler.checkIfExists();
// Process HTML with options
await htmlHandler.processHtml({
from: './src/index.html', // Source HTML (default: './html/index.html')
to: './dist/index.html', // Output HTML (default: './dist_serve/index.html')
minify: true, // Enable minification
});
```
### AssetsHandler Class
Handle static assets (images, fonts, etc.):
```typescript
import { AssetsHandler } from '@git.zone/tsbundle';
const assetsHandler = new AssetsHandler();
// Ensure assets directory exists
await assetsHandler.ensureAssetsDir();
// Copy and process assets
await assetsHandler.processAssets({
from: './src/assets', // Source directory (default: './assets')
to: './dist/assets', // Output directory (default: './dist_serve/assets')
});
```
## Advanced Examples
### Building a Modern Web Application
```typescript
import { TsBundle, HtmlHandler, AssetsHandler } from '@git.zone/tsbundle';
async function buildWebApp() {
const bundler = new TsBundle();
const htmlHandler = new HtmlHandler();
const assetsHandler = new AssetsHandler();
// Bundle the JavaScript
await bundler.build(process.cwd(), './src/app.ts', './dist/app.js', {
bundler: 'rolldown',
production: true,
});
// Process HTML
await htmlHandler.processHtml({
from: './src/index.html',
to: './dist/index.html',
minify: true,
});
// Copy assets
await assetsHandler.processAssets({
from: './src/assets',
to: './dist/assets',
});
console.log('Build complete!');
}
buildWebApp();
```
### Multi-Entry Point Bundling
```typescript
import { TsBundle } from '@git.zone/tsbundle';
async function buildMultipleEntries() {
const bundler = new TsBundle();
const entries = [
{ from: './src/main.ts', to: './dist/main.js' },
{ from: './src/admin.ts', to: './dist/admin.js' },
{ from: './src/worker.ts', to: './dist/worker.js' },
];
for (const entry of entries) {
await bundler.build(process.cwd(), entry.from, entry.to, {
bundler: 'esbuild',
});
}
}
```
### Development vs Production Builds
```typescript
import { TsBundle } from '@git.zone/tsbundle';
const bundler = new TsBundle();
const isDev = process.env.NODE_ENV === 'development';
await bundler.build(
process.cwd(),
'./src/index.ts',
isDev ? './dist/dev/bundle.js' : './dist/prod/bundle.min.js',
{
bundler: isDev ? 'esbuild' : 'rolldown', // esbuild for speed in dev
production: !isDev, // minify in production
commonjs: false, // use ES modules
},
);
```
## TypeScript Configuration
tsbundle works best with the following TypeScript configuration:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true
}
}
```
## Best Practices
1. **Entry Points**: Keep your entry points in `ts_web/` for web bundles or `ts/` for library bundles
2. **Output Structure**: Use `dist_bundle/` for bundled files and `dist_serve/` for web-ready files
3. **Bundler Selection**:
- Use `esbuild` for development (fastest)
- Use `rolldown` or `rspack` for production (better optimization)
4. **Assets**: Place static assets in the `assets/` directory
5. **HTML**: Keep HTML templates in the `html/` directory
## License and Legal Information
This repository contains open-source code that is licensed under the MIT License. A copy of the MIT License can be found in the [license](license) file within this repository.
**Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
### Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH and are not included within the scope of the MIT license granted herein. Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines, and any usage must be approved in writing by Task Venture Capital GmbH.
### Company Information
Task Venture Capital GmbH
Registered at District court Bremen HRB 35230 HB, Germany
For any legal inquiries or if you require further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

126
readme.plan.md Normal file
View File

@@ -0,0 +1,126 @@
# tsbundle Rolldown Integration Plan
**Command to reread CLAUDE.md**: `cat ~/.claude/CLAUDE.md`
## 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.
## Current State
- tsbundle currently only uses esbuild despite having interfaces for multiple bundlers
- The bundler selection logic exists but always returns esbuild
- mod_rollup and mod_parcel directories exist but are empty
- Recent commits disabled splitting and tree-shaking in esbuild due to issues
## Implementation Tasks
### Phase 1: Core Infrastructure
- [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] Remove hardcoded `bundler: 'esbuild'` from transportOptions (line 26)
- [x] Add rolldown dependency to package.json: `"rolldown": "^1.0.0-beta.18"`
### Phase 2: CLI Support
- [x] Check if `ts/tsbundle.cli.ts` already parses --bundler option
- [x] Ensure default bundler is 'esbuild' when not specified
- [x] Verify CLI passes bundler option correctly to TsBundle class
### Phase 3: Rolldown Module Implementation
- [x] Create `ts/mod_rolldown/` directory
- [x] Create `ts/mod_rolldown/plugins.ts`:
```typescript
export * from '../plugins.js';
import { rolldown } from 'rolldown';
export { rolldown };
```
- [x] Create `ts/mod_rolldown/index.child.ts` with:
- TsBundleProcess class
- getAliases() method for tsconfig path resolution
- buildTest() method (sourcemaps, no minification)
- buildProduction() method (minified output)
- run() function to read transportOptions and execute
### Phase 4: Feature Parity
- [x] Implement TypeScript compilation via rolldown
- [x] Ensure source map generation works
- [x] Support tsconfig path aliases
- [x] Match esbuild's ESM output format
- [x] Implement minification for production builds
- [x] Handle bundle: true behavior
### Phase 5: Testing
- [x] Test default behavior (should use esbuild)
- [x] Test `--bundler=esbuild` explicit selection
- [x] Test `--bundler=rolldown` selection
- [x] Compare output between esbuild and rolldown
- [ ] Verify all existing tests pass with both bundlers
## Technical Specifications
### Rolldown Configuration Mapping
| esbuild option | rolldown equivalent |
| ---------------- | ----------------------------------- |
| bundle: true | bundle: true |
| sourcemap: true | sourcemap: true |
| format: 'esm' | format: 'es' |
| target: 'es2022' | (use default, no direct equivalent) |
| minify: true | minify: true |
| entryPoints | input |
| outfile | output.file |
| tsconfig | resolve.tsconfigFilename |
| alias | resolve.alias |
### CLI Usage
```bash
# Default (uses esbuild)
tsbundle
# Use rolldown
tsbundle --bundler=rolldown
# Production build with rolldown
tsbundle --production --bundler=rolldown
```
## Risks and Mitigation
1. **Rolldown is beta** - Keep esbuild as default, mark rolldown as experimental
2. **API differences** - Abstract common interface, handle bundler-specific logic
3. **Missing features** - Document any limitations in README
4. **Breaking changes** - None, as esbuild remains default
## Success Criteria
- [x] Can build with esbuild (default behavior unchanged)
- [x] Can build with rolldown via --bundler flag
- [x] Both bundlers produce working ESM output
- [x] Source maps work with both bundlers
- [x] TypeScript compilation works with both
- [ ] All existing tests pass
## Implementation Status
**COMPLETED** - Rolldown has been successfully integrated as an optional bundler.
### Test Results:
- esbuild (default): Working correctly, 2.2K minified
- rolldown: Working correctly, 1.5K minified (better compression!)
- Both bundlers support all required features
- CLI properly routes to selected bundler
- Production and test modes work for both
## Future Considerations
- Once Rolldown reaches v1.0.0 stable, consider making it default
- Implement rollup and parcel modules using same pattern
- Add performance benchmarks comparing bundlers
- Consider adding --watch mode support

View File

@@ -15,7 +15,10 @@
<!--Lets make sure we support older browsers-->
<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-->
<style>
@@ -62,13 +65,11 @@
}
</style>
<div class="container">
<div class="header">
We need JavaScript to run properly!
</div>
<div class="header">We need JavaScript to run properly!</div>
<div class="content">
This site is being built using lit-element (made by Google). This technology works with
JavaScript. Subsequently this website does not work as intended by Lossless GmbH without
JavaScript.
This site is being built using lit-element (made by Google). This
technology works with JavaScript. Subsequently this website does not
work as intended by Lossless GmbH without JavaScript.
</div>
</div>
<div class="footer">

44
test/test-decorators.ts Normal file
View File

@@ -0,0 +1,44 @@
// 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),
);

View File

@@ -1,40 +1,108 @@
import { expect, tap } from '@pushrocks/tapbundle';
import * as tsbundle from '../ts/index.js';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import * as tsbundle from '../dist_ts/index.js';
import * as path from 'path';
import * as fs from 'fs';
const testBundler = async (
bundlerName: 'esbuild' | 'rolldown' | 'rspack',
mode: 'test' | 'production',
) => {
const outputFile = `./dist_manual/${bundlerName}-${mode}.js`;
const testDir = path.join(process.cwd(), 'test');
// Clean up output directory
const outputDir = path.join(testDir, 'dist_manual');
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Clean up output file if exists
const outputPath = path.join(testDir, outputFile);
if (fs.existsSync(outputPath)) {
fs.rmSync(outputPath, { force: true });
}
tap.test('should bundle with esbuild', async () => {
const tsbundleInstance = new tsbundle.TsBundle();
await tsbundleInstance.build(
process.cwd() + '/test',
'./ts_web/index.ts',
'./dist_manual/test.js',
{
bundler: 'esbuild'
}
);
await tsbundleInstance.build(testDir, './ts_web/index.ts', outputFile, {
bundler: bundlerName,
production: mode === 'production',
});
// Verify output file was created
expect(fs.existsSync(outputPath)).toBeTrue();
console.log(`${bundlerName} ${mode} mode: success`);
};
// Test esbuild
tap.test('should bundle with esbuild in test mode', async () => {
await testBundler('esbuild', 'test');
});
tap.test('should bundle with parcel', async () => {
const tsbundleInstance = new tsbundle.TsBundle();
await tsbundleInstance.build(
process.cwd() + '/test',
'./ts_web/index.ts',
'./dist_manual/test.js',
{
bundler: 'parcel'
}
);
tap.test('should bundle with esbuild in production mode', async () => {
await testBundler('esbuild', 'production');
});
tap.test('should bundle with rollup', async () => {
const tsbundleInstance = new tsbundle.TsBundle();
await tsbundleInstance.build(
process.cwd(),
'./test/ts_web/index.ts',
'./test/dist_manual/production.js',
{bundler: 'rollup'}
);
// Test rolldown
tap.test('should bundle with rolldown in test mode', async () => {
await testBundler('rolldown', 'test');
});
tap.test('should bundle with rolldown in production mode', async () => {
await testBundler('rolldown', 'production');
});
// Test rspack
tap.test('should bundle with rspack in test mode', async () => {
await testBundler('rspack', 'test');
});
tap.test('should bundle with rspack in production mode', async () => {
await testBundler('rspack', 'production');
});
// Test size comparison
tap.test('should show bundle size comparison', async () => {
const testDir = path.join(process.cwd(), 'test');
const sizes: Record<string, { test: number; production: number }> = {
esbuild: { test: 0, production: 0 },
rolldown: { test: 0, production: 0 },
rspack: { test: 0, production: 0 },
};
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
for (const mode of ['test', 'production'] as const) {
const filePath = path.join(testDir, `dist_manual/${bundler}-${mode}.js`);
if (fs.existsSync(filePath)) {
const stats = fs.statSync(filePath);
sizes[bundler][mode] = stats.size;
}
}
}
console.log('\n📊 Bundle Size Comparison:');
console.log('┌─────────────┬────────────┬──────────────┐');
console.log('│ Bundler │ Test Mode │ Production │');
console.log('├─────────────┼────────────┼──────────────┤');
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
const testSize = (sizes[bundler].test / 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('└─────────────┴────────────┴──────────────┘');
// Verify all sizes are reasonable
for (const bundler of ['esbuild', 'rolldown', 'rspack'] as const) {
expect(sizes[bundler].test).toBeGreaterThan(0);
expect(sizes[bundler].production).toBeGreaterThan(0);
// Production bundles should generally be smaller due to minification
// but rspack might be larger due to runtime overhead
if (bundler !== 'rspack') {
expect(sizes[bundler].production).toBeLessThan(sizes[bundler].test);
}
}
});
tap.start();

View File

@@ -1,5 +1,9 @@
import * as smartdelay from '@push.rocks/smartdelay';
const myConst: string = 'hello';
await smartdelay.delayFor(1000);
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);

35
test/ts_web/test-lit.ts Normal file
View File

@@ -0,0 +1,35 @@
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
:host {
display: block;
padding: 16px;
}
`;
@property({ type: String })
name = 'World';
@property({ type: Number })
count = 0;
render() {
return html`
<h1>Hello, ${this.name}!</h1>
<button @click=${this._onClick}>Click Count: ${this.count}</button>
`;
}
private _onClick() {
this.count++;
}
}
// Test instantiation
const element = new MyElement();
console.log('Element created:', element);
console.log('Element name:', element.name);
console.log('Element count:', element.count);

8
ts/00_commitinfo_data.ts Normal file
View File

@@ -0,0 +1,8 @@
/**
* autocreated commitinfo by @push.rocks/commitinfo
*/
export const commitinfo = {
name: '@git.zone/tsbundle',
version: '2.6.0',
description: 'a multi-bundler tool supporting esbuild, rolldown, and rspack for painless bundling of web projects'
}

View File

@@ -1,4 +1,4 @@
import * as early from '@pushrocks/early';
import * as early from '@push.rocks/early';
early.start('tsbundle');
// lets import all plugins beforehand
import './plugins.js';
@@ -9,5 +9,6 @@ early.stop();
// lets make this usable programmatically
export * from './tsbundle.class.tsbundle.js';
export * from './mod_assets/index.js';
export * from './mod_html/index.js';
export { runCli };

View File

@@ -2,13 +2,13 @@ export interface ICliOptions {
commonjs?: boolean;
skiplibcheck?: boolean;
production?: boolean;
bundler: 'parcel' | 'esbuild' | 'rollup'
bundler: 'esbuild' | 'rolldown' | 'rspack';
}
export interface IEnvTransportOptions {
cwd: string;
from: string;
to: string;
mode: 'test' | 'production',
argv: ICliOptions
mode: 'test' | 'production';
argv: ICliOptions;
}

68
ts/mod_assets/index.ts Normal file
View File

@@ -0,0 +1,68 @@
import * as plugins from './plugins.js';
import * as paths from '../paths.js';
export class AssetsHandler {
public defaultFromDirPath: string = plugins.path.join(paths.cwd, './assets');
public defaultToDirPath: string = plugins.path.join(
paths.cwd,
'./dist_serve/assets',
);
public async ensureAssetsDir() {
const dirExists = await plugins.fs
.directory(this.defaultFromDirPath)
.exists();
if (!dirExists) {
await plugins.fs.directory(this.defaultFromDirPath).create();
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
public async processAssets(optionsArg?: { from?: string; to?: string }) {
// lets assemble the options
optionsArg = {
...{
from: this.defaultFromDirPath,
to: this.defaultToDirPath,
},
...(optionsArg || {}),
};
await this.ensureAssetsDir();
optionsArg.from = plugins.smartpath.transform.toAbsolute(
optionsArg.from,
paths.cwd,
) as string;
optionsArg.to = plugins.smartpath.transform.toAbsolute(
optionsArg.to,
paths.cwd,
) as string;
// lets clean the target directory
const toExists = await plugins.fs.directory(optionsArg.to).exists();
if (toExists) {
await plugins.fs.directory(optionsArg.to).delete();
}
await this.copyDirectoryRecursive(optionsArg.from, optionsArg.to);
}
}

1
ts/mod_assets/plugins.ts Normal file
View File

@@ -0,0 +1 @@
export * from '../plugins.js';

View File

@@ -1,75 +1,118 @@
import * as plugins from './plugins.js';
import * as paths from '../paths.js';
import * as interfaces from '../interfaces/index.js';
import { logger } from '../tsbundle.logging.js';
export class TsBundleProcess {
constructor() {
// Nothing here
}
public async getAliases() {
try {
const aliasObject: Record<string, string> = {};
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
const tsconfigContent = await plugins.fs
.file(tsconfigPath)
.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)) {
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
aliasObject[alias] = aliasPath;
}
}
return aliasObject;
} catch (error) {
return {};
}
}
/**
* creates a bundle for the test enviroment
*/
public async buildTest(
fromArg: string,
toArg: string,
argvArg: any
) {
public async buildTest(fromArg: string, toArg: string, argvArg: any) {
// create a bundle
const esbuild = await plugins.esbuild.build({
entryPoints: [fromArg],
bundle: true,
sourcemap: true,
format: 'esm',
outfile: toArg
target: 'es2022',
entryNames: plugins.path.parse(toArg).name,
outdir: plugins.path.parse(toArg).dir,
splitting: false,
treeShaking: false,
tsconfig: paths.tsconfigPath,
alias: await this.getAliases(),
});
}
/**
* creates a bundle for the production environment
*/
public async buildProduction(
fromArg: string,
toArg: string,
argvArg: any
) {
public async buildProduction(fromArg: string, toArg: string, argvArg: any) {
// create a bundle
console.log('esbuild specific:');
console.log(`from: ${fromArg}`);
console.log((`to: ${toArg}`));
console.log(`to: ${toArg}`);
const esbuild = await plugins.esbuild.build({
entryPoints: [fromArg],
bundle: true,
sourcemap: true,
format: 'esm',
target: 'es2022',
minify: true,
outfile: toArg
entryNames: plugins.path.parse(toArg).name,
outdir: plugins.path.parse(toArg).dir,
tsconfig: paths.tsconfigPath,
splitting: false,
treeShaking: false,
chunkNames: 'chunks/[name]-[hash]',
alias: await this.getAliases(),
});
}
}
const run = async () => {
console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(process.env.transportOptions);
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
process.env.transportOptions,
);
console.log('=======> ESBUILD');
console.log(transportOptions);
process.chdir(transportOptions.cwd);
console.log(`switched to ${process.cwd()}`);
const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') {
console.log('building for test:')
console.log('building for test:');
tsbundleProcessInstance.buildTest(
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
transportOptions.argv
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
} else {
console.log('building for production:')
console.log('building for production:');
tsbundleProcessInstance.buildProduction(
plugins.smartpath.transform.makeAbsolute(transportOptions.from, process.cwd()),
plugins.smartpath.transform.makeAbsolute(transportOptions.to, process.cwd()),
transportOptions.argv
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
}
};

View File

@@ -2,6 +2,4 @@ export * from '../plugins.js';
import esbuild from 'esbuild';
export {
esbuild
}
export { esbuild };

View File

@@ -2,43 +2,63 @@ import * as plugins from './plugins.js';
import * as paths from '../paths.js';
export class HtmlHandler {
public defaultFromPath: string = plugins.path.join(paths.htmlDir, 'index.html');
public defaultToPath: string = plugins.path.join(paths.distServeDir, 'index.html');
public defaultFromPath: string = plugins.path.join(
paths.htmlDir,
'index.html',
);
public defaultToPath: string = plugins.path.join(
paths.distServeDir,
'index.html',
);
public async checkIfExists() {
return plugins.smartfile.fs.fileExists(this.defaultFromPath);
return await plugins.fs.file(this.defaultFromPath).exists();
}
// copies the html
public async copyHtml(fromArg: string = this.defaultFromPath, toArg: string = this.defaultToPath) {
public async processHtml(optionsArg: {
from?: string;
to?: string;
minify?: boolean;
}) {
optionsArg = {
...{
from: this.defaultFromPath,
to: this.defaultToPath,
minify: false,
},
...optionsArg,
};
if (await this.checkIfExists()) {
console.log(`${fromArg} replaces file at ${toArg}`);
console.log(`${optionsArg.from} replaces file at ${optionsArg.to}`);
}
fromArg = plugins.smartpath.transform.toAbsolute(fromArg, paths.cwd) as string;
toArg = plugins.smartpath.transform.toAbsolute(toArg, paths.cwd) as string;
await plugins.smartfile.fs.copy(fromArg, toArg);
console.log(`html copy succeeded!`);
}
// copies and minifies the html
public async minifyHtml(fromArg: string = this.defaultFromPath, toArg: string = this.defaultToPath) {
if (await this.checkIfExists()) {
console.log(`${fromArg} replaces file at ${toArg}`);
optionsArg.from = plugins.smartpath.transform.toAbsolute(
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) {
fileString = plugins.htmlMinifier.minify(fileString, {
minifyCSS: true,
minifyJS: true,
sortAttributes: true,
sortClassName: true,
removeAttributeQuotes: true,
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeComments: true,
});
}
fromArg = plugins.smartpath.transform.toAbsolute(fromArg, paths.cwd) as string;
toArg = plugins.smartpath.transform.toAbsolute(toArg, paths.cwd) as string;
const fileString = plugins.smartfile.fs.toStringSync(fromArg);
const minifiedHtml = plugins.htmlMinifier.minify(fileString, {
minifyCSS: true,
minifyJS: true,
sortAttributes: true,
sortClassName: true,
removeAttributeQuotes: true,
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeComments: true,
});
await plugins.smartfile.memory.toFs(minifiedHtml, toArg);
console.log(`html minification succeeded!`);
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!`);
}
}

View File

@@ -2,6 +2,4 @@ export * from '../plugins.js';
import * as htmlMinifier from 'html-minifier';
export {
htmlMinifier
}
export { htmlMinifier };

View File

@@ -1,70 +0,0 @@
import * as plugins from './plugins.js';
import * as interfaces from '../interfaces/index.js';
import { logger } from '../tsbundle.logging.js';
export class TsBundleProcess {
constructor() {
// Nothing here
}
/**
* creates a bundle for the test enviroment
*/
public async buildTest (
fromArg: string,
toArg: string,
argvArg: any
) {
const parsedPath = plugins.path.parse(toArg);
const parcelInstance = new plugins.smartparcel.Parcel(
fromArg,
parsedPath.dir,
parsedPath.base
);
await parcelInstance.build();
}
/**
* creates a bundle for the production environment
*/
public async buildProduction (
fromArg: string,
toArg: string,
argvArg: any
) {
// create a bundle
const parsedPath = plugins.path.parse(toArg);
const parcelInstance = new plugins.smartparcel.Parcel(
fromArg,
parsedPath.dir,
parsedPath.base
);
await parcelInstance.build();
}
}
const run = async () => {
console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(process.env.transportOptions);
console.log('bundling with parcel:');
console.log(transportOptions);
process.chdir(transportOptions.cwd);
console.log(`switched to ${process.cwd()}`);
const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') {
tsbundleProcessInstance.buildTest(
transportOptions.from,
transportOptions.to,
transportOptions.argv
);
} else {
tsbundleProcessInstance.buildProduction(
transportOptions.from,
transportOptions.to,
transportOptions.argv
);
}
};
run();

View File

@@ -1,7 +0,0 @@
export * from '../plugins.js'
import * as smartparcel from '@pushrocks/smartparcel';
export {
smartparcel
}

View File

@@ -0,0 +1,130 @@
import * as plugins from './plugins.js';
import * as paths from '../paths.js';
import * as interfaces from '../interfaces/index.js';
import { logger } from '../tsbundle.logging.js';
export class TsBundleProcess {
constructor() {
// Nothing here
}
public async getAliases() {
try {
const aliasObject: Record<string, string> = {};
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
const tsconfigContent = await plugins.fs
.file(tsconfigPath)
.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)) {
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
aliasObject[alias] = aliasPath;
}
}
return aliasObject;
} catch (error) {
return {};
}
}
/**
* creates a bundle for the test enviroment
*/
public async buildTest(fromArg: string, toArg: string, argvArg: any) {
// create a bundle
const result = await plugins.rolldown({
input: fromArg,
resolve: {
alias: await this.getAliases(),
tsconfigFilename: paths.tsconfigPath,
},
});
const outputDir = plugins.path.dirname(toArg);
const outputFilename = plugins.path.basename(toArg);
await result.write({
dir: outputDir,
entryFileNames: outputFilename,
format: 'es',
sourcemap: true,
inlineDynamicImports: true,
});
}
/**
* creates a bundle for the production environment
*/
public async buildProduction(fromArg: string, toArg: string, argvArg: any) {
// create a bundle
console.log('rolldown specific:');
console.log(`from: ${fromArg}`);
console.log(`to: ${toArg}`);
const result = await plugins.rolldown({
input: fromArg,
resolve: {
alias: await this.getAliases(),
tsconfigFilename: paths.tsconfigPath,
},
});
const outputDir = plugins.path.dirname(toArg);
const outputFilename = plugins.path.basename(toArg);
await result.write({
dir: outputDir,
entryFileNames: outputFilename,
format: 'es',
sourcemap: true,
minify: true,
inlineDynamicImports: true,
});
}
}
const run = async () => {
console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
process.env.transportOptions,
);
console.log('=======> ROLLDOWN');
console.log(transportOptions);
process.chdir(transportOptions.cwd);
console.log(`switched to ${process.cwd()}`);
const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') {
console.log('building for test:');
await tsbundleProcessInstance.buildTest(
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
} else {
console.log('building for production:');
await tsbundleProcessInstance.buildProduction(
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
}
};
run();

View File

@@ -0,0 +1,5 @@
export * from '../plugins.js';
import { rolldown } from 'rolldown';
export { rolldown };

View File

@@ -1,162 +0,0 @@
import * as plugins from './plugins.js';
import * as interfaces from '../interfaces/index.js';
import { logger } from '../tsbundle.logging.js';
export class TsBundleProcess {
/**
* the basic default options for rollup
*/
public getBaseOptions(
fromArg: string = `ts_web/index.ts`,
toArg: string = 'dist_bundle/bundle.js',
argvArg: any
) {
logger.log('info', `from: ${fromArg}`);
logger.log('info', `to: ${toArg}`);
const baseOptions: plugins.rollup.RollupOptions = {
input: fromArg,
output: {
name: 'tsbundle',
file: toArg,
format: 'iife',
sourcemap: true,
},
// Indicate here external modules you don't wanna include in your bundle (i.e.: 'lodash')
external: [],
watch: {
include: ['src/**'],
},
plugins: [
// Compile TypeScript files
(plugins.rollupTypescript as any)({
include: plugins.path.parse(fromArg).dir
? plugins.path.parse(fromArg).dir + '/**/*.ts'
: '**/*.ts',
declaration: false,
emitDecoratorMetadata: true,
experimentalDecorators: true,
inlineSourceMap: true,
noEmitOnError: true,
lib: ['dom'],
noImplicitAny: false,
target: 'es2020',
module: 'es2020',
moduleResolution: 'node12',
allowSyntheticDefaultImports: true,
importsNotUsedAsValues: 'preserve',
...(argvArg && argvArg.skiplibcheck
? {
skipLibCheck: true,
}
: {}),
...(argvArg && argvArg.allowimplicitany
? {
noImplicitAny: false,
}
: {}),
...(argvArg && argvArg.commonjs
? {
module: 'commonjs',
moduleResolution: 'node',
}
: {}),
}),
(plugins.rollupJson as any)(),
// Allow node_modules resolution, so you can use 'external' to control
// which external modules to include in the bundle
// https://github.com/rollup/rollup-plugin-node-resolve#usage
plugins.rollupResolve(),
(plugins.rollupCommonjs as any)({}),
// Resolve source maps to the original source
plugins.rollupSourceMaps(),
],
};
return baseOptions;
}
public getOptionsTest(
fromArg: string,
toArg: string,
argvArg: any
): plugins.rollup.RollupOptions {
return this.getBaseOptions(fromArg, toArg, argvArg);
}
public getOptionsProduction(
fromArg: string,
toArg: string,
argvArg: any
): plugins.rollup.RollupOptions {
const productionOptions = this.getBaseOptions(fromArg, toArg, argvArg);
productionOptions.plugins.push(
plugins.rollupTerser({
compress: true,
mangle: true,
})
);
return productionOptions;
}
constructor() {
// Nothing here
}
/**
* creates a bundle for the test enviroment
*/
public async buildTest(
fromArg: string,
toArg: string,
argvArg: any
) {
// create a bundle
logger.log('info', `bundling for TEST!`);
const buildOptions = this.getOptionsTest(fromArg, toArg, argvArg);
const bundle = await plugins.rollup.rollup(buildOptions);
bundle.generate(buildOptions.output as plugins.rollup.OutputOptions);
await bundle.write(buildOptions.output as plugins.rollup.OutputOptions);
logger.log('ok', `Successfully bundled files!`);
process.exit(0);
}
/**
* creates a bundle for the production environment
*/
public async buildProduction(fromArg: string, toArg: string, argvArg: any) {
// create a bundle
logger.log('info', `bundling for PRODUCTION!`);
const buildOptions = this.getOptionsProduction(fromArg, toArg, argvArg);
const bundle = await plugins.rollup.rollup(buildOptions);
bundle.generate(buildOptions.output as plugins.rollup.OutputOptions);
await bundle.write(buildOptions.output as plugins.rollup.OutputOptions);
logger.log('ok', `Successfully bundled files!`);
process.exit(0);
}
}
const run = async () => {
console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(process.env.transportOptions);
console.log('bundling with rollup:');
console.log(transportOptions);
process.chdir(transportOptions.cwd);
console.log(`switched to ${process.cwd()}`);
const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') {
tsbundleProcessInstance.buildTest(
transportOptions.from,
transportOptions.to,
transportOptions.argv
);
} else {
tsbundleProcessInstance.buildProduction(
transportOptions.from,
transportOptions.to,
transportOptions.argv
);
}
};
run();

View File

@@ -1,22 +0,0 @@
export * from '../plugins.js';
// third party scope
import * as rollup from 'rollup';
import rollupBabel from 'rollup-plugin-babel';
import rollupCommonjs from '@rollup/plugin-commonjs';
import rollupJson from '@rollup/plugin-json';
import rollupResolve from '@rollup/plugin-node-resolve';
import rollupSourceMaps from 'rollup-plugin-sourcemaps';
import { terser as rollupTerser } from 'rollup-plugin-terser';
import rollupTypescript from '@rollup/plugin-typescript';
export {
rollup,
rollupBabel,
rollupCommonjs,
rollupJson,
rollupResolve,
rollupSourceMaps,
rollupTerser,
rollupTypescript,
};

View File

@@ -0,0 +1,261 @@
import * as plugins from './plugins.js';
import * as paths from '../paths.js';
import * as interfaces from '../interfaces/index.js';
import { logger } from '../tsbundle.logging.js';
export class TsBundleProcess {
constructor() {
// Nothing here
}
public async getAliases() {
try {
const aliasObject: Record<string, string> = {};
const tsconfigPath = plugins.path.join(paths.cwd, 'tsconfig.json');
const tsconfigContent = await plugins.fs
.file(tsconfigPath)
.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)) {
const aliasPath = localTsConfig.compilerOptions.paths[alias][0];
// Convert TypeScript path to absolute path for rspack
aliasObject[alias.replace('/*', '')] = plugins.path.resolve(
paths.cwd,
aliasPath.replace('/*', ''),
);
}
}
return aliasObject;
} catch (error) {
return {};
}
}
/**
* creates a bundle for the test enviroment
*/
public async buildTest(fromArg: string, toArg: string, argvArg: any) {
const aliases = await this.getAliases();
const outputDir = plugins.path.dirname(toArg);
const outputFilename = plugins.path.basename(toArg);
const config = {
mode: 'development' as const,
entry: {
main: fromArg,
},
output: {
path: outputDir,
filename: outputFilename,
library: {
type: 'module' as const,
},
},
devtool: 'source-map' as const,
resolve: {
alias: aliases,
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: true,
},
target: 'es2022',
transform: {
decoratorVersion: '2022-03',
},
},
},
},
type: 'javascript/auto',
},
],
},
experiments: {
outputModule: true,
},
};
return new Promise((resolve, reject) => {
plugins.rspack(config, (err, stats) => {
if (err) {
console.error(err.stack || err);
reject(err);
return;
}
if (stats.hasErrors()) {
console.error(stats.toString());
reject(new Error('Build failed with errors'));
return;
}
console.log(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}),
);
resolve(undefined);
});
});
}
/**
* creates a bundle for the production environment
*/
public async buildProduction(fromArg: string, toArg: string, argvArg: any) {
console.log('rspack specific:');
console.log(`from: ${fromArg}`);
console.log(`to: ${toArg}`);
const aliases = await this.getAliases();
const outputDir = plugins.path.dirname(toArg);
const outputFilename = plugins.path.basename(toArg);
const config = {
mode: 'production' as const,
entry: {
main: fromArg,
},
output: {
path: outputDir,
filename: outputFilename,
library: {
type: 'module' as const,
},
},
devtool: 'source-map' as const,
resolve: {
alias: aliases,
extensions: ['.ts', '.tsx', '.js', '.jsx'],
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: {
loader: 'builtin:swc-loader',
options: {
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: true,
},
target: 'es2022',
transform: {
decoratorVersion: '2022-03',
},
minify: {
compress: true,
mangle: true,
},
},
},
},
type: 'javascript/auto',
},
],
},
optimization: {
minimize: true,
concatenateModules: true,
usedExports: true,
sideEffects: true,
},
experiments: {
outputModule: true,
},
};
return new Promise((resolve, reject) => {
plugins.rspack(config, (err, stats) => {
if (err) {
console.error(err.stack || err);
reject(err);
return;
}
if (stats.hasErrors()) {
console.error(stats.toString());
reject(new Error('Build failed with errors'));
return;
}
console.log(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}),
);
resolve(undefined);
});
});
}
}
const run = async () => {
console.log('running spawned compilation process');
const transportOptions: interfaces.IEnvTransportOptions = JSON.parse(
process.env.transportOptions,
);
console.log('=======> RSPACK');
console.log(transportOptions);
process.chdir(transportOptions.cwd);
console.log(`switched to ${process.cwd()}`);
const tsbundleProcessInstance = new TsBundleProcess();
if (transportOptions.mode === 'test') {
console.log('building for test:');
await tsbundleProcessInstance.buildTest(
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
} else {
console.log('building for production:');
await tsbundleProcessInstance.buildProduction(
plugins.smartpath.transform.makeAbsolute(
transportOptions.from,
process.cwd(),
),
plugins.smartpath.transform.makeAbsolute(
transportOptions.to,
process.cwd(),
),
transportOptions.argv,
);
}
};
run();

5
ts/mod_rspack/plugins.ts Normal file
View File

@@ -0,0 +1,5 @@
export * from '../plugins.js';
import { rspack } from '@rspack/core';
export { rspack };

View File

@@ -3,8 +3,9 @@ import * as plugins from './plugins.js';
export const cwd = process.cwd();
export const packageDir = plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
'../'
'../',
);
export const htmlDir = plugins.path.join(cwd, './html');
export const distServeDir = plugins.path.join(cwd, './dist_serve');
export const assetsDir = plugins.path.join(packageDir, 'assets');
export const tsconfigPath = plugins.path.join(assetsDir, './tsconfig.json');

View File

@@ -4,20 +4,23 @@ import * as path from 'path';
export { path };
// pushrocks scope
import * as smartcli from '@pushrocks/smartcli';
import * as smartfile from '@pushrocks/smartfile';
import * as smartlog from '@pushrocks/smartlog';
import * as smartlogDestinationLocal from '@pushrocks/smartlog-destination-local';
import * as smartpath from '@pushrocks/smartpath';
import * as smartpromise from '@pushrocks/smartpromise';
import * as smartspawn from '@pushrocks/smartspawn';
import * as smartcli from '@push.rocks/smartcli';
import * as smartfs from '@push.rocks/smartfs';
import * as smartlog from '@push.rocks/smartlog';
import * as smartlogDestinationLocal from '@push.rocks/smartlog-destination-local';
import * as smartpath from '@push.rocks/smartpath';
import * as smartpromise from '@push.rocks/smartpromise';
import * as smartspawn from '@push.rocks/smartspawn';
export {
smartcli,
smartfile,
smartfs,
smartlog,
smartlogDestinationLocal,
smartpath,
smartpromise,
smartspawn,
};
// Create a shared SmartFs instance using Node provider
export const fs = new smartfs.SmartFs(new smartfs.SmartFsProviderNode());

View File

@@ -3,40 +3,37 @@ import * as interfaces from './interfaces/index.js';
import { logger } from './tsbundle.logging.js';
export class TsBundle {
public async build(
cwdArg: string,
fromArg: string = './ts_web/index.ts',
toArg: string = './dist_bundle/bundle.js',
argvArg: interfaces.ICliOptions
argvArg: interfaces.ICliOptions,
) {
const done = plugins.smartpromise.defer();
const getBundlerPath = () => {
if (argvArg.bundler === 'esbuild') {
return './mod_esbuild/index.child.js'
switch (argvArg.bundler) {
case 'rolldown':
return './mod_rolldown/index.child.js';
case 'rspack':
return './mod_rspack/index.child.js';
case 'esbuild':
default:
return './mod_esbuild/index.child.js';
}
if (argvArg.bundler === 'parcel') {
return './mod_parcel/index.child.js'
}
if (argvArg.bundler === 'rollup') {
return './mod_rollup/index.child.js'
}
return './mod_esbuild/index.child.js'
}
};
const transportOptions: interfaces.IEnvTransportOptions = {
cwd: cwdArg,
from: fromArg,
to: toArg,
mode: argvArg && argvArg.production ? 'production' : 'test',
argv: {
bundler: 'esbuild',
...argvArg
}
}
argv: {
...argvArg,
},
};
const threadsimple = new plugins.smartspawn.ThreadSimple(
plugins.path.join(
plugins.smartpath.get.dirnameFromImportMetaUrl(import.meta.url),
getBundlerPath()
getBundlerPath(),
),
[],
{
@@ -44,7 +41,7 @@ export class TsBundle {
...process.env,
transportOptions: JSON.stringify(transportOptions),
},
}
},
);
const childProcess = await threadsimple.start();
childProcess.on('exit', (status) => {

View File

@@ -2,10 +2,11 @@ import * as plugins from './plugins.js';
import { TsBundle } from './tsbundle.class.tsbundle.js';
import { HtmlHandler } from './mod_html/index.js';
import { logger } from './tsbundle.logging.js';
import { AssetsHandler } from './mod_assets/index.js';
export const runCli = async () => {
const tsBundleCli = new plugins.smartcli.Smartcli();
tsBundleCli.standardTask().subscribe(async (argvArg) => {
tsBundleCli.standardCommand().subscribe(async (argvArg) => {
const tsbundle = new TsBundle();
await tsbundle.build(process.cwd(), argvArg.from, argvArg.to, argvArg);
return;
@@ -13,13 +14,11 @@ export const runCli = async () => {
tsBundleCli.addCommand('element').subscribe(async (argvArg) => {
const tsbundle = new TsBundle();
const htmlHandler = new HtmlHandler();
// const htmlHandler = new HtmlHandler();
await tsbundle.build(
process.cwd(),
'./ts_web/index.ts',
'./dist_bundle/bundle.js',
argvArg
argvArg,
);
});
@@ -30,20 +29,42 @@ export const runCli = async () => {
process.cwd(),
'./ts/index.ts',
'./dist_bundle/bundle.js',
argvArg
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
argvArg,
);
await htmlHandler.minifyHtml('./html/index.html', './dist_serve/index.html')
const htmlDirPath = plugins.path.join(process.cwd(), './html');
let htmlFiles: string[] = [];
const htmlDirExists = await plugins.fs.directory(htmlDirPath).exists();
if (htmlDirExists) {
const entries = await plugins.fs
.directory(htmlDirPath)
.filter(/\.html$/)
.list();
htmlFiles = entries.map((entry) => entry.path);
}
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();

View File

@@ -12,4 +12,6 @@ export const logger = new plugins.smartlog.Smartlog({
minimumLogLevel: 'silly',
});
logger.addLogDestination(new plugins.smartlogDestinationLocal.DestinationLocal());
logger.addLogDestination(
new plugins.smartlogDestinationLocal.DestinationLocal(),
);

View File

@@ -1,9 +1,12 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node12",
"esModuleInterop": true
}
}
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true,
"baseUrl": ".",
"paths": {}
},
"exclude": ["dist_*/**/*.d.ts"]
}

View File

@@ -1,17 +0,0 @@
{
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
}