rolldown 1.0.0-beta.1-commit.7c52c94 → 1.0.0-beta.2-commit.f069c5d

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/cjs/cli.cjs +981 -25
  2. package/dist/cjs/experimental-index.cjs +2 -2
  3. package/dist/cjs/index.cjs +2 -2
  4. package/dist/cjs/parallel-plugin-worker.cjs +2 -2
  5. package/dist/cjs/parse-ast-index.cjs +1 -1
  6. package/dist/esm/cli.mjs +981 -26
  7. package/dist/esm/experimental-index.mjs +2 -2
  8. package/dist/esm/index.mjs +2 -2
  9. package/dist/esm/parallel-plugin-worker.mjs +2 -2
  10. package/dist/esm/parse-ast-index.mjs +1 -1
  11. package/dist/shared/{binding-Bl7VQy7c.mjs → binding-l7VLSKnB.mjs} +3 -3
  12. package/dist/shared/{binding-fhgdIkpS.cjs → binding-orkvONpS.cjs} +3 -3
  13. package/dist/shared/prompt-B7tq3GL9.cjs +854 -0
  14. package/dist/shared/prompt-Nfm4Xz36.mjs +851 -0
  15. package/dist/shared/{src-lBcHSsjm.cjs → src-BRzD1T3r.cjs} +12 -6
  16. package/dist/shared/{src-CPCP99Z9.mjs → src-Cmr3pg11.mjs} +12 -6
  17. package/dist/types/api/build.js +22 -0
  18. package/dist/types/api/experimental.js +13 -0
  19. package/dist/types/api/rolldown/index.js +7 -0
  20. package/dist/types/api/rolldown/rolldown-build.js +43 -0
  21. package/dist/types/api/watch/index.js +8 -0
  22. package/dist/types/api/watch/watch-emitter.js +69 -0
  23. package/dist/types/api/watch/watcher.js +66 -0
  24. package/dist/types/binding.d.ts +40 -2
  25. package/dist/types/builtin-plugin/alias-plugin.js +4 -0
  26. package/dist/types/builtin-plugin/constructors.d.ts +2 -2
  27. package/dist/types/builtin-plugin/constructors.js +68 -0
  28. package/dist/types/builtin-plugin/replace-plugin.js +29 -0
  29. package/dist/types/builtin-plugin/transform-plugin.js +16 -0
  30. package/dist/types/builtin-plugin/utils.js +19 -0
  31. package/dist/types/cli/arguments/alias.js +63 -0
  32. package/dist/types/cli/arguments/index.js +127 -0
  33. package/dist/types/cli/arguments/normalize.js +48 -0
  34. package/dist/types/cli/arguments/utils.js +67 -0
  35. package/dist/types/cli/colors.js +17 -0
  36. package/dist/types/cli/commands/bundle.js +203 -0
  37. package/dist/types/cli/commands/help.js +88 -0
  38. package/dist/types/cli/index.js +27 -0
  39. package/dist/types/cli/load-config.js +95 -0
  40. package/dist/types/cli/logger.js +35 -0
  41. package/dist/types/constants/plugin-context.js +7 -0
  42. package/dist/types/constants/plugin.js +69 -0
  43. package/dist/types/experimental-index.js +9 -0
  44. package/dist/types/index.d.ts +2 -2
  45. package/dist/types/index.js +7 -0
  46. package/dist/types/log/logHandler.js +25 -0
  47. package/dist/types/log/logger.js +107 -0
  48. package/dist/types/log/logging.js +11 -0
  49. package/dist/types/log/logs.js +86 -0
  50. package/dist/types/options/input-options.d.ts +47 -2
  51. package/dist/types/options/input-options.js +1 -0
  52. package/dist/types/options/normalized-input-options.js +21 -0
  53. package/dist/types/options/normalized-output-options.js +99 -0
  54. package/dist/types/options/output-options.d.ts +6 -0
  55. package/dist/types/options/output-options.js +1 -0
  56. package/dist/types/options/watch-options.js +1 -0
  57. package/dist/types/parallel-plugin-worker.js +31 -0
  58. package/dist/types/parallel-plugin.js +1 -0
  59. package/dist/types/parse-ast-index.js +73 -0
  60. package/dist/types/plugin/bindingify-build-hooks.js +213 -0
  61. package/dist/types/plugin/bindingify-hook-filter.js +39 -0
  62. package/dist/types/plugin/bindingify-output-hooks.js +189 -0
  63. package/dist/types/plugin/bindingify-plugin-hook-meta.js +19 -0
  64. package/dist/types/plugin/bindingify-plugin.js +124 -0
  65. package/dist/types/plugin/bindingify-watch-hooks.js +29 -0
  66. package/dist/types/plugin/hook-filter.js +1 -0
  67. package/dist/types/plugin/index.js +1 -0
  68. package/dist/types/plugin/minimal-plugin-context.js +25 -0
  69. package/dist/types/plugin/parallel-plugin-implementation.js +3 -0
  70. package/dist/types/plugin/parallel-plugin.js +6 -0
  71. package/dist/types/plugin/plugin-context-data.js +55 -0
  72. package/dist/types/plugin/plugin-context.js +108 -0
  73. package/dist/types/plugin/plugin-driver.js +88 -0
  74. package/dist/types/plugin/transform-plugin-context.js +37 -0
  75. package/dist/types/types/assert.js +1 -0
  76. package/dist/types/types/config-export.js +1 -0
  77. package/dist/types/types/misc.js +1 -0
  78. package/dist/types/types/module-info.js +1 -0
  79. package/dist/types/types/module-side-effects.js +1 -0
  80. package/dist/types/types/output-bundle.js +1 -0
  81. package/dist/types/types/rolldown-options.js +1 -0
  82. package/dist/types/types/rolldown-output.js +1 -0
  83. package/dist/types/types/schema.js +1 -0
  84. package/dist/types/types/sourcemap.js +16 -0
  85. package/dist/types/types/utils.js +1 -0
  86. package/dist/types/utils/asset-source.js +8 -0
  87. package/dist/types/utils/async-flatten.js +7 -0
  88. package/dist/types/utils/bindingify-input-options.js +225 -0
  89. package/dist/types/utils/bindingify-output-options.js +92 -0
  90. package/dist/types/utils/code-frame.js +46 -0
  91. package/dist/types/utils/compose-js-plugins.js +400 -0
  92. package/dist/types/utils/create-bundler-option.js +53 -0
  93. package/dist/types/utils/create-bundler.js +15 -0
  94. package/dist/types/utils/define-config.js +3 -0
  95. package/dist/types/utils/error.js +65 -0
  96. package/dist/types/utils/initialize-parallel-plugins.js +54 -0
  97. package/dist/types/utils/misc.js +22 -0
  98. package/dist/types/utils/normalize-hook.js +21 -0
  99. package/dist/types/utils/normalize-plugin-option.js +35 -0
  100. package/dist/types/utils/normalize-string-or-regex.js +14 -0
  101. package/dist/types/utils/plugin/index.js +7 -0
  102. package/dist/types/utils/transform-module-info.js +19 -0
  103. package/dist/types/utils/transform-rendered-chunk.js +43 -0
  104. package/dist/types/utils/transform-rendered-module.js +10 -0
  105. package/dist/types/utils/transform-side-effects.js +16 -0
  106. package/dist/types/utils/transform-sourcemap.js +29 -0
  107. package/dist/types/utils/transform-to-rollup-output.js +165 -0
  108. package/dist/types/utils/validator.js +275 -0
  109. package/package.json +28 -25
  110. package/dist/shared/consola_36c0034f-Cx52UqEq.mjs +0 -832
  111. package/dist/shared/consola_36c0034f-CynBWXXO.cjs +0 -859
  112. package/dist/shared/prompt-B58MxVuU.cjs +0 -762
  113. package/dist/shared/prompt-DjjlOckE.mjs +0 -758
  114. package/dist/tsconfig.dts.tsbuildinfo +0 -1
@@ -0,0 +1,127 @@
1
+ import { alias } from './alias';
2
+ import { camelCaseToKebabCase, flattenSchema, getSchemaType, kebabCaseToCamelCase, } from './utils';
3
+ import { parseArgs } from 'node:util';
4
+ import { normalizeCliOptions } from './normalize';
5
+ import { logger } from '../logger';
6
+ import { getJsonSchema } from '../../utils/validator';
7
+ const objectSchema = getJsonSchema();
8
+ export const flattenedSchema = flattenSchema(objectSchema.properties);
9
+ export const options = Object.fromEntries(Object.entries(flattenedSchema).map(([key, schema]) => {
10
+ const config = Object.getOwnPropertyDescriptor(alias, key)?.value;
11
+ const type = getSchemaType(schema);
12
+ const result = {
13
+ type: type === 'boolean' ? 'boolean' : 'string',
14
+ // We only support comma separated mode right now.
15
+ // multiple: type === 'object' || type === 'array',
16
+ description: schema?.description ?? config?.description ?? '',
17
+ hint: config?.hint,
18
+ };
19
+ if (config && config?.abbreviation) {
20
+ result.short = config?.abbreviation;
21
+ }
22
+ if (config && config.reverse) {
23
+ if (result.description.startsWith('enable')) {
24
+ result.description = result.description.replace('enable', 'disable');
25
+ }
26
+ else {
27
+ result.description = `disable ${result.description}`;
28
+ }
29
+ }
30
+ key = camelCaseToKebabCase(key);
31
+ // add 'no-' prefix for need reverse options
32
+ return [config?.reverse ? `no-${key}` : key, result];
33
+ }));
34
+ export function parseCliArguments() {
35
+ const { values, tokens, positionals } = parseArgs({
36
+ options,
37
+ tokens: true,
38
+ allowPositionals: true,
39
+ // We can't use `strict` mode because we should handle the default config file name.
40
+ strict: false,
41
+ });
42
+ tokens
43
+ .filter((token) => token.kind === 'option')
44
+ .forEach((option) => {
45
+ let negative = false;
46
+ if (option.name.startsWith('no-')) {
47
+ // stripe `no-` prefix
48
+ const name = kebabCaseToCamelCase(option.name.substring(3));
49
+ if (name in flattenedSchema) {
50
+ // Remove the `no-` in values
51
+ delete values[option.name];
52
+ option.name = name;
53
+ negative = true;
54
+ }
55
+ }
56
+ delete values[option.name]; // Strip the kebab-case options.
57
+ option.name = kebabCaseToCamelCase(option.name);
58
+ let originalType = flattenedSchema[option.name];
59
+ if (!originalType) {
60
+ logger.error(`Invalid option: ${option.rawName}. We will ignore this option.`);
61
+ // We will refuse to handle the invalid option, as it may cause unexpected behavior.
62
+ process.exit(1);
63
+ }
64
+ let type = getSchemaType(originalType);
65
+ if (type === 'string' && typeof option.value !== 'string') {
66
+ let opt = option;
67
+ // We should use the default value.
68
+ let defaultValue = Object.getOwnPropertyDescriptor(alias, opt.name)
69
+ ?.value;
70
+ Object.defineProperty(values, opt.name, {
71
+ value: defaultValue.default ?? '',
72
+ enumerable: true,
73
+ configurable: true,
74
+ writable: true,
75
+ });
76
+ }
77
+ else if (type === 'object' && typeof option.value === 'string') {
78
+ const [key, value] = option.value.split(',').map((x) => x.split('='))[0];
79
+ if (!values[option.name]) {
80
+ Object.defineProperty(values, option.name, {
81
+ value: {},
82
+ enumerable: true,
83
+ configurable: true,
84
+ writable: true,
85
+ });
86
+ }
87
+ if (key && value) {
88
+ // TODO support multiple entries.
89
+ Object.defineProperty(values[option.name], key, {
90
+ value,
91
+ enumerable: true,
92
+ configurable: true,
93
+ writable: true,
94
+ });
95
+ }
96
+ }
97
+ else if (type === 'array' && typeof option.value === 'string') {
98
+ if (!values[option.name]) {
99
+ Object.defineProperty(values, option.name, {
100
+ value: [],
101
+ enumerable: true,
102
+ configurable: true,
103
+ writable: true,
104
+ });
105
+ }
106
+ ;
107
+ values[option.name].push(option.value);
108
+ }
109
+ else if (type === 'boolean') {
110
+ Object.defineProperty(values, option.name, {
111
+ value: !negative,
112
+ enumerable: true,
113
+ configurable: true,
114
+ writable: true,
115
+ });
116
+ }
117
+ else {
118
+ Object.defineProperty(values, option.name, {
119
+ value: option.value ?? '',
120
+ enumerable: true,
121
+ configurable: true,
122
+ writable: true,
123
+ });
124
+ }
125
+ });
126
+ return normalizeCliOptions(values, positionals);
127
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * @description This file is used for normalize the options.
3
+ * In CLI, the input options and output options are mixed together. We need to tell them apart.
4
+ */
5
+ import { logger } from '../logger';
6
+ import { setNestedProperty } from './utils';
7
+ import { getInputCliKeys, getOutputCliKeys, validateCliOptions, } from '../../utils/validator';
8
+ export function normalizeCliOptions(cliOptions, positionals) {
9
+ const [data, errors] = validateCliOptions(cliOptions);
10
+ if (errors?.length) {
11
+ errors.forEach((error) => {
12
+ logger.error(`Invalid value for option ${error}. You can use \`rolldown -h\` to see the help.`);
13
+ });
14
+ process.exit(1);
15
+ }
16
+ const options = data ?? {};
17
+ const result = {
18
+ input: {},
19
+ output: {},
20
+ help: options.help ?? false,
21
+ version: options.version ?? false,
22
+ watch: options.watch ?? false,
23
+ };
24
+ if (typeof options.config === 'string') {
25
+ result.config = options.config;
26
+ }
27
+ const keysOfInput = getInputCliKeys();
28
+ const keysOfOutput = getOutputCliKeys();
29
+ const reservedKeys = ['help', 'version', 'config', 'watch'];
30
+ for (let [key, value] of Object.entries(options)) {
31
+ const keys = key.split('.');
32
+ const [primary] = keys;
33
+ if (keysOfInput.includes(primary)) {
34
+ setNestedProperty(result.input, key, value);
35
+ }
36
+ else if (keysOfOutput.includes(primary)) {
37
+ setNestedProperty(result.output, key, value);
38
+ }
39
+ else if (!reservedKeys.includes(key)) {
40
+ logger.error(`Unknown option: ${key}`);
41
+ process.exit(1);
42
+ }
43
+ }
44
+ if (!result.config && positionals.length > 0) {
45
+ result.input.input = positionals;
46
+ }
47
+ return result;
48
+ }
@@ -0,0 +1,67 @@
1
+ const priority = [
2
+ 'object',
3
+ 'array',
4
+ 'string',
5
+ 'number',
6
+ 'boolean',
7
+ ];
8
+ export function getSchemaType(schema) {
9
+ if ('anyOf' in schema) {
10
+ const types = schema.anyOf.map(getSchemaType);
11
+ // Order: object > array > string > number > boolean
12
+ let result = priority.find((type) => types.includes(type));
13
+ if (result) {
14
+ return result;
15
+ }
16
+ }
17
+ if ('type' in schema) {
18
+ return schema.type;
19
+ }
20
+ if ('const' in schema) {
21
+ return typeof schema.const;
22
+ }
23
+ return 'object';
24
+ }
25
+ export function flattenSchema(schema, base = {}, parent = '') {
26
+ if (schema === undefined) {
27
+ return base;
28
+ }
29
+ for (const [k, value] of Object.entries(schema)) {
30
+ const key = parent ? `${parent}.${k}` : k;
31
+ if (getSchemaType(value) === 'object') {
32
+ if ('properties' in value) {
33
+ flattenSchema(value.properties, base, key);
34
+ }
35
+ else {
36
+ base[key] = value;
37
+ }
38
+ }
39
+ else {
40
+ base[key] = value;
41
+ }
42
+ }
43
+ return base;
44
+ }
45
+ export function setNestedProperty(obj, path, value) {
46
+ const keys = path.split('.');
47
+ let current = obj;
48
+ for (let i = 0; i < keys.length - 1; i++) {
49
+ if (!current[keys[i]]) {
50
+ current[keys[i]] = {};
51
+ }
52
+ current = current[keys[i]];
53
+ }
54
+ const finalKey = keys[keys.length - 1];
55
+ Object.defineProperty(current, finalKey, {
56
+ value: value,
57
+ writable: true,
58
+ enumerable: true,
59
+ configurable: true,
60
+ });
61
+ }
62
+ export function camelCaseToKebabCase(str) {
63
+ return str.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
64
+ }
65
+ export function kebabCaseToCamelCase(str) {
66
+ return str.replace(/-./g, (match) => match[1].toUpperCase());
67
+ }
@@ -0,0 +1,17 @@
1
+ import { env } from 'node:process';
2
+ import { createColors } from 'colorette';
3
+ // @see https://no-color.org
4
+ // @see https://www.npmjs.com/package/chalk
5
+ const { bold, cyan, dim, gray, green, red, underline, yellow, } = createColors({
6
+ useColor: env.FORCE_COLOR !== '0' && !env.NO_COLOR,
7
+ });
8
+ export const colors = {
9
+ bold,
10
+ cyan,
11
+ dim,
12
+ gray,
13
+ green,
14
+ red,
15
+ underline,
16
+ yellow,
17
+ };
@@ -0,0 +1,203 @@
1
+ import path from 'node:path';
2
+ import { performance } from 'node:perf_hooks';
3
+ import { onExit } from 'signal-exit';
4
+ import { colors } from '../colors';
5
+ import { logger } from '../logger';
6
+ import { arraify } from '../../utils/misc';
7
+ import { rolldown } from '../../api/rolldown';
8
+ import { watch as rolldownWatch } from '../../api/watch';
9
+ import { loadConfig } from '../load-config';
10
+ export async function bundleWithConfig(configPath, cliOptions) {
11
+ const config = await loadConfig(configPath);
12
+ if (!config) {
13
+ logger.error(`No configuration found at ${config}`);
14
+ process.exit(1);
15
+ }
16
+ // TODO: Could add more validation/diagnostics here to emit a nice error message
17
+ if (cliOptions.watch) {
18
+ await watchInner(config, cliOptions);
19
+ }
20
+ else {
21
+ await bundleInner(config, cliOptions);
22
+ }
23
+ }
24
+ export async function bundleWithCliOptions(cliOptions) {
25
+ if (cliOptions.output.dir || cliOptions.output.file) {
26
+ const operation = cliOptions.watch ? watchInner : bundleInner;
27
+ await operation({}, cliOptions);
28
+ return;
29
+ }
30
+ if (cliOptions.watch) {
31
+ logger.error('You must specify `output.dir` to use watch mode');
32
+ process.exit(1);
33
+ }
34
+ // Rolldown doesn't yet support the following syntax:
35
+ // await using build = await rolldown(cliOptions.input)
36
+ const build = await rolldown(cliOptions.input);
37
+ try {
38
+ const { output: outputs } = await build.generate(cliOptions.output);
39
+ if (outputs.length === 0) {
40
+ logger.error('No output generated');
41
+ process.exit(1);
42
+ }
43
+ for (const file of outputs) {
44
+ if (outputs.length > 1) {
45
+ logger.log(`\n${colors.cyan(colors.bold(`|→ ${file.fileName}:`))}\n`);
46
+ }
47
+ // avoid consola since it doesn't print it as raw string
48
+ // eslint-disable-next-line no-console
49
+ console.log(file.type === 'asset' ? file.source : file.code);
50
+ }
51
+ }
52
+ finally {
53
+ await build.close();
54
+ }
55
+ }
56
+ async function watchInner(config, cliOptions) {
57
+ // Only if watch is true in CLI can we use watch mode.
58
+ // We should not make it `await`, as it never ends.
59
+ let normalizedConfig = arraify(config).map((option) => {
60
+ return {
61
+ ...option,
62
+ ...cliOptions.input,
63
+ output: arraify(option.output || {}).map((output) => {
64
+ return {
65
+ ...output,
66
+ ...cliOptions.output,
67
+ };
68
+ }),
69
+ };
70
+ });
71
+ const watcher = await rolldownWatch(normalizedConfig);
72
+ onExit((code) => {
73
+ Promise.resolve(watcher.close()).finally(() => {
74
+ process.exit(typeof code === 'number' ? code : 0);
75
+ });
76
+ return true;
77
+ });
78
+ const changedFile = [];
79
+ watcher.on('change', (id, event) => {
80
+ if (event.event === 'update') {
81
+ changedFile.push(id);
82
+ }
83
+ });
84
+ watcher.on('event', (event) => {
85
+ switch (event.code) {
86
+ case 'BUNDLE_START':
87
+ if (changedFile.length > 0) {
88
+ logger.log(`Found ${colors.bold(changedFile.map(relativeId).join(', '))} changed, rebuilding...`);
89
+ }
90
+ changedFile.length = 0;
91
+ break;
92
+ case 'BUNDLE_END':
93
+ logger.success(`Rebuilt ${colors.bold(relativeId(event.output[0]))} in ${colors.bold(ms(event.duration))}.`);
94
+ break;
95
+ case 'ERROR':
96
+ logger.error(event.error);
97
+ break;
98
+ default:
99
+ break;
100
+ }
101
+ });
102
+ logger.log(`Waiting for changes...`);
103
+ }
104
+ async function bundleInner(config, cliOptions) {
105
+ const startTime = performance.now();
106
+ const result = [];
107
+ const configList = arraify(config);
108
+ for (const config of configList) {
109
+ const outputList = arraify(config.output || {});
110
+ const build = await rolldown({ ...config, ...cliOptions.input });
111
+ for (const output of outputList) {
112
+ // run multiply instance at sequential
113
+ try {
114
+ result.push(await build.write({
115
+ ...output,
116
+ ...cliOptions.output,
117
+ }));
118
+ }
119
+ finally {
120
+ await build.close();
121
+ }
122
+ }
123
+ }
124
+ result.forEach(printBundleOutputPretty);
125
+ logger.log(``);
126
+ const endTime = performance.now();
127
+ const duration = endTime - startTime;
128
+ // If the build time is more than 1s, we should display it in seconds.
129
+ logger.success(`Finished in ${colors.bold(ms(duration))}`);
130
+ }
131
+ function printBundleOutputPretty(output) {
132
+ const outputEntries = collectOutputEntries(output.output);
133
+ const outputLayoutSizes = collectOutputLayoutAdjustmentSizes(outputEntries);
134
+ printOutputEntries(outputEntries, outputLayoutSizes, '<DIR>');
135
+ }
136
+ function collectOutputEntries(output) {
137
+ return output.map((chunk) => ({
138
+ type: chunk.type,
139
+ fileName: chunk.fileName,
140
+ size: chunk.type === 'chunk' ? chunk.code.length : chunk.source.length,
141
+ }));
142
+ }
143
+ function collectOutputLayoutAdjustmentSizes(entries) {
144
+ let longest = 0;
145
+ let biggestSize = 0;
146
+ for (const entry of entries) {
147
+ if (entry.fileName.length > longest) {
148
+ longest = entry.fileName.length;
149
+ }
150
+ if (entry.size > biggestSize) {
151
+ biggestSize = entry.size;
152
+ }
153
+ }
154
+ const sizePad = displaySize(biggestSize).length;
155
+ return {
156
+ longest,
157
+ biggestSize,
158
+ sizePad,
159
+ };
160
+ }
161
+ const numberFormatter = new Intl.NumberFormat('en', {
162
+ maximumFractionDigits: 2,
163
+ minimumFractionDigits: 2,
164
+ });
165
+ function displaySize(bytes) {
166
+ return `${numberFormatter.format(bytes / 1000)} kB`;
167
+ }
168
+ const CHUNK_GROUPS = [
169
+ { type: 'asset', color: 'green' },
170
+ { type: 'chunk', color: 'cyan' },
171
+ ];
172
+ function printOutputEntries(entries, sizeAdjustment, distPath) {
173
+ for (const group of CHUNK_GROUPS) {
174
+ const filtered = entries.filter((e) => e.type === group.type);
175
+ if (!filtered.length) {
176
+ continue;
177
+ }
178
+ for (const entry of filtered.sort((a, z) => a.size - z.size)) {
179
+ // output format: `path/to/xxx type | size: y.yy kB`
180
+ let log = colors.dim(withTrailingSlash(distPath));
181
+ log += colors[group.color](entry.fileName.padEnd(sizeAdjustment.longest + 2));
182
+ log += colors.dim(entry.type);
183
+ log += colors.dim(` │ size: ${displaySize(entry.size).padStart(sizeAdjustment.sizePad)}`);
184
+ logger.log(log);
185
+ }
186
+ }
187
+ }
188
+ function withTrailingSlash(path) {
189
+ if (path[path.length - 1] !== '/') {
190
+ return `${path}/`;
191
+ }
192
+ return path;
193
+ }
194
+ function ms(duration) {
195
+ return duration < 1000
196
+ ? `${duration.toFixed(2)} ms`
197
+ : `${(duration / 1000).toFixed(2)} s`;
198
+ }
199
+ function relativeId(id) {
200
+ if (!path.isAbsolute(id))
201
+ return id;
202
+ return path.relative(path.resolve(), id);
203
+ }
@@ -0,0 +1,88 @@
1
+ import { logger } from '../logger';
2
+ import { version, description, } from '../../../package.json' assert { type: 'json' };
3
+ import { colors } from '../colors';
4
+ import { options } from '../arguments';
5
+ import { camelCaseToKebabCase } from '../arguments/utils';
6
+ const introduction = `${colors.gray(`${description} (rolldown v${version})`)}
7
+
8
+ ${colors.bold(colors.underline('USAGE'))} ${colors.cyan('rolldown -c <config>')} or ${colors.cyan('rolldown <input> <options>')}`;
9
+ const examples = [
10
+ {
11
+ title: 'Bundle with a config file `rolldown.config.mjs`',
12
+ command: 'rolldown -c rolldown.config.mjs',
13
+ },
14
+ {
15
+ title: 'Bundle the `src/main.ts` to `dist` with `cjs` format',
16
+ command: 'rolldown src/main.ts -d dist -f cjs',
17
+ },
18
+ {
19
+ title: 'Bundle the `src/main.ts` and handle the `.png` assets to Data URL',
20
+ command: 'rolldown src/main.ts -d dist --moduleTypes .png=dataurl',
21
+ },
22
+ {
23
+ title: 'Bundle the `src/main.tsx` and minify the output with sourcemap',
24
+ command: 'rolldown src/main.tsx -d dist -m -s',
25
+ },
26
+ {
27
+ title: 'Create self-executing IIFE using external jQuery as `$` and `_`',
28
+ command: 'rolldown src/main.ts -d dist -n bundle -f iife -e jQuery,window._ -g jQuery=$',
29
+ },
30
+ ];
31
+ const notes = [
32
+ 'Due to the API limitation, you need to pass `-s` for `.map` sourcemap file as the last argument.',
33
+ 'If you are using the configuration, please pass the `-c` as the last argument if you ignore the default configuration file.',
34
+ 'CLI options will override the configuration file.',
35
+ 'For more information, please visit https://rolldown.rs/.',
36
+ ];
37
+ export function showHelp() {
38
+ logger.log(introduction);
39
+ logger.log('');
40
+ logger.log(`${colors.bold(colors.underline('OPTIONS'))}`);
41
+ logger.log('');
42
+ logger.log(Object.entries(options)
43
+ .sort(([a], [b]) => {
44
+ // 1. If one of them has a short option, prioritize it.
45
+ if (options[a].short && !options[b].short) {
46
+ return -1;
47
+ }
48
+ if (!options[a].short && options[b].short) {
49
+ return 1;
50
+ }
51
+ // 2. If both of them have a short option, sort by the short letter.
52
+ if (options[a].short && options[b].short) {
53
+ return options[a].short.localeCompare(options[b].short);
54
+ }
55
+ // 3. If none of them has a short option, sort by the long option.
56
+ return a.localeCompare(b);
57
+ })
58
+ .map(([option, { type, short, hint, description }]) => {
59
+ let optionStr = ` --${option} `;
60
+ option = camelCaseToKebabCase(option);
61
+ if (short) {
62
+ optionStr += `-${short}, `;
63
+ }
64
+ if (type === 'string') {
65
+ optionStr += `<${hint ?? option}>`;
66
+ }
67
+ if (description && description.length > 0) {
68
+ description = description[0].toUpperCase() + description.slice(1);
69
+ }
70
+ return (colors.cyan(optionStr.padEnd(30)) +
71
+ description +
72
+ (description && description?.endsWith('.') ? '' : '.'));
73
+ })
74
+ .join('\n'));
75
+ logger.log('');
76
+ logger.log(`${colors.bold(colors.underline('EXAMPLES'))}`);
77
+ logger.log('');
78
+ examples.forEach(({ title, command }, ord) => {
79
+ logger.log(` ${ord + 1}. ${title}:`);
80
+ logger.log(` ${colors.cyan(command)}`);
81
+ logger.log('');
82
+ });
83
+ logger.log(`${colors.bold(colors.underline('NOTES'))}`);
84
+ logger.log('');
85
+ notes.forEach((note) => {
86
+ logger.log(` * ${colors.gray(note)}`);
87
+ });
88
+ }
@@ -0,0 +1,27 @@
1
+ import process from 'node:process';
2
+ import { bundleWithCliOptions, bundleWithConfig } from './commands/bundle';
3
+ import { logger } from './logger';
4
+ import { parseCliArguments } from './arguments';
5
+ import { showHelp } from './commands/help';
6
+ import { version } from '../../package.json';
7
+ async function main() {
8
+ const cliOptions = parseCliArguments();
9
+ if (cliOptions.config || cliOptions.config === '') {
10
+ await bundleWithConfig(cliOptions.config, cliOptions);
11
+ return;
12
+ }
13
+ if ('input' in cliOptions.input) {
14
+ // If input is specified, we will bundle with the input options
15
+ await bundleWithCliOptions(cliOptions);
16
+ return;
17
+ }
18
+ if (cliOptions.version) {
19
+ logger.log(`rolldown v${version}`);
20
+ return;
21
+ }
22
+ showHelp();
23
+ }
24
+ main().catch((err) => {
25
+ console.error(err);
26
+ process.exit(1);
27
+ });
@@ -0,0 +1,95 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { cwd } from 'node:process';
4
+ import { readdir } from 'node:fs/promises';
5
+ import { pathToFileURL } from 'node:url';
6
+ import { rolldown } from '../api/rolldown';
7
+ async function bundleTsConfig(configFile) {
8
+ const dirnameVarName = 'injected_original_dirname';
9
+ const filenameVarName = 'injected_original_filename';
10
+ const importMetaUrlVarName = 'injected_original_import_meta_url';
11
+ const bundle = await rolldown({
12
+ input: configFile,
13
+ platform: 'node',
14
+ resolve: {
15
+ mainFields: ['main'],
16
+ },
17
+ define: {
18
+ __dirname: dirnameVarName,
19
+ __filename: filenameVarName,
20
+ 'import.meta.url': importMetaUrlVarName,
21
+ 'import.meta.dirname': dirnameVarName,
22
+ 'import.meta.filename': filenameVarName,
23
+ },
24
+ treeshake: false,
25
+ external: [/^[\w@][^:]/], // external bare imports
26
+ plugins: [
27
+ {
28
+ name: 'inject-file-scope-variables',
29
+ transform: {
30
+ filter: { id: /\.[cm]?[jt]s$/ },
31
+ async handler(code, id) {
32
+ const injectValues = `const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` +
33
+ `const ${filenameVarName} = ${JSON.stringify(id)};` +
34
+ `const ${importMetaUrlVarName} = ${JSON.stringify(pathToFileURL(id).href)};`;
35
+ return { code: injectValues + code, map: null };
36
+ },
37
+ },
38
+ },
39
+ ],
40
+ });
41
+ const outputDir = path.dirname(configFile);
42
+ const result = await bundle.write({
43
+ dir: outputDir,
44
+ format: 'esm',
45
+ sourcemap: 'inline',
46
+ entryFileNames: 'rolldown.config.[hash].js',
47
+ });
48
+ const fileName = result.output.find((chunk) => chunk.type === 'chunk' && chunk.isEntry).fileName;
49
+ return path.join(outputDir, fileName);
50
+ }
51
+ const SUPPORTED_JS_CONFIG_FORMATS = ['.js', '.mjs', '.cjs'];
52
+ const SUPPORTED_TS_CONFIG_FORMATS = ['.ts', '.mts', '.cts'];
53
+ const SUPPORTED_CONFIG_FORMATS = [
54
+ ...SUPPORTED_JS_CONFIG_FORMATS,
55
+ ...SUPPORTED_TS_CONFIG_FORMATS,
56
+ ];
57
+ const DEFAULT_CONFIG_BASE = 'rolldown.config';
58
+ async function findConfigFileNameInCwd() {
59
+ const filesInWorkingDirectory = new Set(await readdir(cwd()));
60
+ for (const extension of SUPPORTED_CONFIG_FORMATS) {
61
+ const fileName = `${DEFAULT_CONFIG_BASE}${extension}`;
62
+ if (filesInWorkingDirectory.has(fileName))
63
+ return fileName;
64
+ }
65
+ throw new Error('No `rolldown.config` configuration file found.');
66
+ }
67
+ export async function loadTsConfig(configFile) {
68
+ const file = await bundleTsConfig(configFile);
69
+ try {
70
+ return (await import(pathToFileURL(file).href)).default;
71
+ }
72
+ finally {
73
+ fs.unlink(file, () => { }); // Ignore errors
74
+ }
75
+ }
76
+ export async function loadConfig(configPath) {
77
+ const ext = path.extname((configPath = configPath || (await findConfigFileNameInCwd())));
78
+ try {
79
+ if (SUPPORTED_JS_CONFIG_FORMATS.includes(ext) ||
80
+ (process.env.NODE_OPTIONS?.includes('--import=tsx') &&
81
+ SUPPORTED_TS_CONFIG_FORMATS.includes(ext))) {
82
+ return (await import(pathToFileURL(configPath).href)).default;
83
+ }
84
+ else if (SUPPORTED_TS_CONFIG_FORMATS.includes(ext)) {
85
+ const rawConfigPath = path.resolve(configPath);
86
+ return await loadTsConfig(rawConfigPath);
87
+ }
88
+ else {
89
+ throw new Error(`Unsupported config format. Expected: \`${SUPPORTED_CONFIG_FORMATS.join(',')}\` but got \`${ext}\``);
90
+ }
91
+ }
92
+ catch (err) {
93
+ throw new Error('Error happened while loading config.', { cause: err });
94
+ }
95
+ }