Compare commits

..

67 Commits

Author SHA1 Message Date
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
c53d9023fe 1.0.101 2022-03-18 16:16:20 +01:00
1112cfe793 fix(core): update 2022-03-18 16:16:20 +01:00
fc97fac77e 1.0.100 2022-03-18 15:46:12 +01:00
1530f0ad74 fix(core): update 2022-03-18 15:46:11 +01:00
36 changed files with 11618 additions and 18725 deletions

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

11
assets/tsconfig.json Normal file
View File

@ -0,0 +1,11 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node12",
"useDefineForClassFields": false,
"preserveValueImports": true,
"esModuleInterop": true
}
}

82
changelog.md Normal file
View File

@ -0,0 +1,82 @@
# Changelog
## 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"
}

18146
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.99",
"name": "@git.zone/tsbundle",
"version": "2.4.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)",
"test": "npm run build && (tstest test/ --verbose)",
"build": "(tsbuild --web --allowimplicitany)"
},
"bin": {
"tsbundle": "cli.js"
},
"devDependencies": {
"@gitzone/tsbuild": "^2.1.56",
"@gitzone/tsrun": "^1.2.31",
"@gitzone/tstest": "^1.0.67",
"@pushrocks/tapbundle": "^5.0.2",
"tslint": "^6.1.3",
"tslint-config-prettier": "^1.15.0"
"@git.zone/tsbuild": "^2.6.4",
"@git.zone/tsrun": "^1.3.3",
"@git.zone/tstest": "^2.3.1",
"@push.rocks/tapbundle": "^6.0.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.11",
"@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartfile": "^11.2.5",
"@push.rocks/smartlog": "^3.1.8",
"@push.rocks/smartlog-destination-local": "^9.0.2",
"@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartspawn": "^3.0.3",
"@types/html-minifier": "^4.0.5",
"esbuild": "^0.25.5",
"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.18",
"@rspack/core": "^1.1.8",
"typescript": "5.8.3"
},
"files": [
"ts/**/*",
@ -67,5 +53,6 @@
],
"browserslist": [
"last 1 chrome versions"
]
],
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
}

10672
pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

49
readme.hints.md Normal file
View File

@ -0,0 +1,49 @@
# tsbundle Hints and Findings
## 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, 2.2K minified
- **rolldown**: Implemented and working (beta), produces smallest bundles (1.5K minified)
- **rspack**: Implemented and working, webpack-compatible API, 6.1K 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

View File

@ -1,8 +1,8 @@
# @gitzone/tsbundle
# @git.zone/tsbundle
a bundler using rollup for painless bundling of web projects
## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@gitzone/tsbundle)
* [npmjs.org (npm package)](https://www.npmjs.com/package/@git.zone/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/)
@ -13,14 +13,14 @@ 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)
npm | [![npm downloads per month](https://badgen.net/npm/dy/@git.zone/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)
PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@git.zone/tsbundle)](https://lossless.cloud)
PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@git.zone/tsbundle)](https://lossless.cloud)
BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@git.zone/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)
## Usage
@ -38,10 +38,10 @@ tsbundle supports two modes of usage: CLI and API usage.
# Install the tool for cli usage
# Globally
npm install -g @gitzone/tsbundle
npm install -g @git.zone/tsbundle
# Locally for use in your pacakge.json
npm install --save-dev @gitzone/tsbundle
npm install --save-dev @git.zone/tsbundle
# then use it
tsbundle --from="./ts/index.ts" --to="dist/bundle.js"

112
readme.plan.md Normal file
View File

@ -0,0 +1,112 @@
# 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

@ -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',
testDir,
'./ts_web/index.ts',
'./dist_manual/test.js',
outputFile,
{
bundler: 'esbuild'
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');
});
// 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;
}
}
}
);
});
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'}
);
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);
@ -15,4 +19,6 @@ class BugReport {
}
}
console.log(myConst);

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.4.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_rollup/htmlhandler.js';
export * from './mod_assets/index.js';
export * from './mod_html/index.js';
export { runCli };

View File

@ -2,7 +2,7 @@ export interface ICliOptions {
commonjs?: boolean;
skiplibcheck?: boolean;
production?: boolean;
bundler: 'parcel' | 'esbuild' | 'rollup'
bundler: 'esbuild' | 'rolldown' | 'rspack'
}
export interface IEnvTransportOptions {

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

@ -0,0 +1,40 @@
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 assetsDirExists = await plugins.smartfile.fs.isDirectory(this.defaultFromDirPath);
if (!assetsDirExists) {
await plugins.smartfile.fs.ensureDir(this.defaultFromDirPath);
console.log(`created assets directory at ${this.defaultFromDirPath}`);
}
}
// 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 theh target directory
await plugins.smartfile.fs.ensureEmptyDir(optionsArg.to);
plugins.smartfile.fs.copySync(optionsArg.from, optionsArg.to, {
replaceTargetDir: true,
});
}
}

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

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

View File

@ -1,71 +1,96 @@
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 localTsConfig = plugins.smartfile.fs.toObjectSync(
plugins.path.join(paths.cwd, 'tsconfig.json')
);
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
);
} 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()),

47
ts/mod_html/index.ts Normal file
View File

@ -0,0 +1,47 @@
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 async checkIfExists() {
return plugins.smartfile.fs.fileExists(this.defaultFromPath);
}
// copies the html
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(`${optionsArg.from} replaces file at ${optionsArg.to}`);
}
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 = plugins.smartfile.fs.toStringSync(optionsArg.from);
if (optionsArg.minify) {
fileString = 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(fileString, optionsArg.to);
console.log(`html processing succeeded!`);
}
}

7
ts/mod_html/plugins.ts Normal file
View File

@ -0,0 +1,7 @@
export * from '../plugins.js';
import * as htmlMinifier from 'html-minifier';
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,115 @@
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 localTsConfig = plugins.smartfile.fs.toObjectSync(
plugins.path.join(paths.cwd, 'tsconfig.json')
);
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,
},
experimental: {
enableComposingJsPlugins: true,
},
});
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,38 +0,0 @@
import * as plugins from './plugins.js';
import * as paths from '../paths.js';
export class HtmlHandler {
public sourceFilePath: string = plugins.path.join(paths.htmlDir, 'index.html');
public targetFilePath: string = plugins.path.join(paths.distServeDir, 'index.html');
public async checkIfExists() {
return plugins.smartfile.fs.fileExists(this.sourceFilePath);
}
// copies the html
public async copyHtml(targetPathArg = this.targetFilePath) {
if (!(await this.checkIfExists())) {
return;
}
await plugins.smartfile.fs.copy(this.sourceFilePath, targetPathArg);
}
// copies and minifies the html
public async minifyHtml(targetPathArg = this.targetFilePath) {
if (!(await this.checkIfExists())) {
return;
}
const fileString = plugins.smartfile.fs.toStringSync(this.sourceFilePath);
const minifiedHtml = plugins.htmlMinifier.minify(fileString, {
minifyCSS: true,
minifyJS: true,
sortAttributes: true,
sortClassName: true,
removeAttributeQuotes: true,
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeComments: true,
});
plugins.smartfile.memory.toFsSync(minifiedHtml, targetPathArg);
}
}

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,25 +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';
import * as htmlMinifier from 'html-minifier';
export {
rollup,
rollupBabel,
rollupCommonjs,
rollupJson,
rollupResolve,
rollupSourceMaps,
rollupTerser,
rollupTypescript,
htmlMinifier,
};

View File

@ -0,0 +1,236 @@
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 localTsConfig = plugins.smartfile.fs.toObjectSync(
plugins.path.join(paths.cwd, 'tsconfig.json')
);
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

@ -8,3 +8,4 @@ export const packageDir = plugins.path.join(
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,13 +4,13 @@ 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 smartfile from '@push.rocks/smartfile';
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,

View File

@ -12,24 +12,23 @@ export class TsBundle {
) {
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: argvArg ? argvArg : {
bundler: 'esbuild'
argv: {
...argvArg
}
}
const threadsimple = new plugins.smartspawn.ThreadSimple(

View File

@ -1,10 +1,12 @@
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;
@ -12,7 +14,6 @@ export const runCli = async () => {
tsBundleCli.addCommand('element').subscribe(async (argvArg) => {
const tsbundle = new TsBundle();
// const htmlHandler = new HtmlHandler();
await tsbundle.build(
process.cwd(),
'./ts_web/index.ts',
@ -23,6 +24,7 @@ export const runCli = async () => {
tsBundleCli.addCommand('npm').subscribe(async (argvArg) => {
const tsbundle = new TsBundle();
const htmlHandler = new HtmlHandler();
await tsbundle.build(
process.cwd(),
'./ts/index.ts',
@ -33,12 +35,27 @@ export const runCli = async () => {
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();

View File

@ -1,9 +1,14 @@
{
"compilerOptions": {
"experimentalDecorators": true,
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node12",
"esModuleInterop": true
}
"useDefineForClassFields": false,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"esModuleInterop": true,
"verbatimModuleSyntax": true
},
"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"
}