Skip to content

Commit a1a4131

Browse files
authored
fix: support script for cjs (#40)
* fix: support script for cjs * fix: socket can not fully transfer data when the flow is too large * fix: build release
1 parent 0675097 commit a1a4131

20 files changed

+555
-168
lines changed

.changeset/fuzzy-crabs-warn.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
'farmup': patch
3+
---
4+
5+
- support script for cjs
6+
- support shebang for file
7+
- fix entry clear failed
8+
- fix can't print address when start html
9+
- bump core version

.editorconfig

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
indent_size = 4
33
indent_style = space
44

5-
[*.{md,json}]
5+
[*.{md,json,yaml}]
66
indent_size = 2

README.md

+15-79
Original file line numberDiff line numberDiff line change
@@ -51,82 +51,18 @@ farmup build index.ts --no-exec
5151

5252
## roadmap
5353

54-
- support more entry file
55-
- more cli options
56-
- sourcemap
57-
- ignore some watch file
58-
- execute without output file
59-
60-
## options
61-
62-
### exec
63-
64-
- `alias`: e
65-
66-
can custom exec, select the exec method by default through the suffix of the file
67-
68-
- html use server star
69-
- ts\js use node
70-
71-
```shell
72-
farmup index.ts -e node
73-
74-
farmup index.ts -e cat
75-
```
76-
77-
### format
78-
79-
- option: `cjs` | `esm`
80-
81-
```shell
82-
farmup --format cjs index.ts
83-
```
84-
85-
### minify
86-
87-
```shell
88-
farmup --minify index.ts
89-
```
90-
91-
### config
92-
93-
custom specify farm config, for more, see [farm config](https://www.farmfe.org/docs/config/configuring-farm)
94-
95-
by default, it automatically finds the configuration
96-
97-
if you not use local config, use `--no-config` option
98-
99-
### target
100-
101-
- `option`: `node``browser`, more see [targetEnv](https://www.farmfe.org/docs/config/compilation-options#outputtargetenv)
102-
103-
define your production environment
104-
105-
### watch
106-
107-
- `alias`: `w`
108-
109-
add extra watch files, support [glob](https://www.npmjs.com/package/glob) pattern
110-
111-
### external
112-
113-
set external package or path
114-
115-
### autoExternal
116-
117-
- `default`: `true`
118-
119-
in your code, if not find `package` or `source`, set external
120-
121-
### sourcemap
122-
123-
- `default`: `undefined`
124-
- option: `boolean` | `'inline'` | `'all'` | `'all-inline'`
125-
126-
generate sourcemap
127-
128-
### no-experience-esm
129-
130-
- option: `boolean`
131-
132-
disable exec esm without output to filesystem
54+
- [ ] support more entry file (without execute)
55+
- [ ] define multiple configurations within a single configuration file.
56+
- [ ] provide more convenient configuration for package library.
57+
- [ ] Integration of some built-in plugins (e.g: `dts`)
58+
- [ ] more cli options
59+
- [ ] sourcemap
60+
- [ ] ignore some watch file
61+
- [ ] support monorepo?
62+
- [x] execute without output file
63+
- [x] cjs
64+
- [x] esm
65+
66+
## option
67+
68+
see [here](./docs/flags.md)

docs/flags.md

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
## options
2+
3+
### exec
4+
5+
- `alias`: e
6+
7+
can custom exec, select the exec method by default through the suffix of the file
8+
9+
- html use server star
10+
- ts\js use node
11+
12+
```shell
13+
farmup index.ts -e node
14+
15+
farmup index.ts -e cat
16+
```
17+
18+
### format
19+
20+
- option: `cjs` | `esm`
21+
22+
```shell
23+
farmup --format cjs index.ts
24+
```
25+
26+
### minify
27+
28+
```shell
29+
farmup --minify index.ts
30+
```
31+
32+
### config
33+
34+
custom specify farm config, for more, see [farm config](https://www.farmfe.org/docs/config/configuring-farm)
35+
36+
by default, it automatically finds the configuration
37+
38+
if you not use local config, use `--no-config` option
39+
40+
### target
41+
42+
- `option`: `node``browser`, more see [targetEnv](https://www.farmfe.org/docs/config/compilation-options#outputtargetenv)
43+
44+
define your production environment
45+
46+
### watch
47+
48+
- `alias`: `w`
49+
50+
add extra watch files, support [glob](https://www.npmjs.com/package/glob) pattern
51+
52+
### external
53+
54+
set external package or path
55+
56+
### autoExternal
57+
58+
- `default`: `true`
59+
60+
in your code, if not find `package` or `source`, set external
61+
62+
### sourcemap
63+
64+
- `default`: `undefined`
65+
- option: `boolean` | `'inline'` | `'all'` | `'all-inline'`
66+
67+
generate sourcemap
68+
69+
### no-experience-script
70+
71+
- option: `boolean`
72+
73+
disable exec esm without output to filesystem

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"private": true,
66
"type": "module",
77
"scripts": {
8+
"initial": "pnpm --filter './packages/core' run build",
89
"dev": "pnpm --filter './packages/core' run dev",
910
"release": "pnpm --filter './packages/*' run build && changeset publish",
1011
"ready": "farmup ./scripts/ready.ts -o ./dist/ready --no-config"
@@ -20,8 +21,9 @@
2021
},
2122
"devDependencies": {
2223
"@biomejs/biome": "^1.7.3",
24+
"@changesets/cli": "^2.27.3",
2325
"cspell": "^8.8.3",
2426
"execa": "^8.0.1",
25-
"@changesets/cli": "^2.27.3"
27+
"rimraf": "^6.0.1"
2628
}
27-
}
29+
}

packages/core/farm.config.cjs.ts

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { defineConfig } from '@farmfe/core';
2+
3+
export default defineConfig({
4+
compilation: {
5+
presetEnv: false,
6+
input: {
7+
vm: './src/node/cjs/vm.ts',
8+
},
9+
output: {
10+
targetEnv: 'node',
11+
format: 'cjs',
12+
entryFilename: '[entryName].cjs',
13+
clean: false,
14+
},
15+
lazyCompilation: false,
16+
persistentCache: false,
17+
external: ['^@farmfe/core$'],
18+
minify: false,
19+
treeShaking: true,
20+
},
21+
});

packages/core/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@
99
"access": "public"
1010
},
1111
"scripts": {
12-
"dev": "farm watch",
13-
"build": "farm build",
12+
"dev": "farm watch & farm watch --config farm.config.cjs.ts",
13+
"build": "rimraf ./dist && farm build && farm build --config farm.config.cjs.ts",
1414
"preview": "farm preview",
1515
"clean": "farm clean",
1616
"farmup": "node ./bin/farmup.js --no-exec -w",
1717
"prepublish": "mv ../../README.md ./"
1818
},
1919
"bin": "./bin/farmup.js",
2020
"devDependencies": {
21-
"@farmfe/cli": "^1.0.4",
21+
"@farmfe/cli": "catalog:",
2222
"@types/fs-extra": "^11.0.4",
2323
"@types/lodash-es": "^4.17.12",
2424
"@types/node": "^20.12.7",
@@ -64,7 +64,7 @@
6464
"email": "[email protected]"
6565
},
6666
"dependencies": {
67-
"@farmfe/core": "^1.3.16",
67+
"@farmfe/core": "catalog:",
6868
"tmp": "^0.2.3"
6969
}
7070
}

packages/core/src/config/normalize/find-entry.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ const formatMapExt: Record<Exclude<Format, undefined>, string> = {
161161
esm: 'mjs',
162162
};
163163

164-
export function pinOutputEntryFilename(options: ResolvedCommonOptions) {
164+
export function pinOutputEntryFilename(options: ResolvedCommonOptions, config: UserConfig) {
165165
if (options.noExecute) return;
166166

167167
const executeMode = options.execute.type;
@@ -171,12 +171,16 @@ export function pinOutputEntryFilename(options: ResolvedCommonOptions) {
171171
}
172172

173173
if (executeMode === ExecuteMode.Node && !options.noExecute) {
174+
const originInput = config.compilation?.input ?? {};
174175
options.entry = Object.entries(options.entry).reduce(
175176
(res, [key, val]) => {
176-
if (val) res[`${key}.${formatMapExt[options.format ?? 'cjs']}`] = val;
177+
if (val) {
178+
if (originInput[key]) res[key] = undefined;
179+
res[`${key}.${formatMapExt[options.format ?? 'cjs']}`] = val;
180+
}
177181
return res;
178182
},
179-
{} as Record<string, string>,
183+
{} as Record<string, string | undefined | null>,
180184
);
181185

182186
options.outputEntry = {

packages/core/src/config/normalize/index.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,12 @@ function normalizedExecuted(commonOption: CommonOptions, options: ResolvedCommon
7777

7878
const execute = options.execute;
7979

80-
if (execute.type === ExecuteMode.Node && commonOption.experienceEsm) {
80+
if (execute.type === ExecuteMode.Node && commonOption.experienceScript) {
8181
if (options.format === 'esm' && !execute.args.includes('--import')) {
8282
execute.args.push('--import', path.join(import.meta.dirname, './import_register.js'));
83+
} else if (options.format === 'cjs' && !execute.args.includes('--experimental-vm-modules')) {
84+
// support dynamic import in vm
85+
execute.args.push('--experimental-vm-modules');
8386
}
8487
}
8588
}
@@ -125,7 +128,6 @@ export function normalizedTargetEnv(
125128
options: ResolvedCommonOptions,
126129
logger: Logger,
127130
) {
128-
config.compilation?.output?.targetEnv;
129131
if (commonOptions.target) {
130132
if (!invalidTargetEnv.includes(commonOptions.target)) {
131133
logger.error(`target ${commonOptions.target} is invalid`);
@@ -176,7 +178,6 @@ async function normalizedSimpleConfig(
176178
logger: Logger,
177179
) {
178180
const inputs = await tryFindEntryFromUserConfig(logger, config, commonOptions);
179-
180181
options.entry = inputs;
181182

182183
config.compilation ??= {};
@@ -207,7 +208,7 @@ async function normalizedSimpleConfig(
207208

208209
normalizedExecuted(commonOptions, options);
209210

210-
pinOutputEntryFilename(options);
211+
pinOutputEntryFilename(options, config);
211212
}
212213

213214
function withServerOrWatch(userConfig: UserConfig, resolvedOption: ResolvedCommonOptions): UserConfig {
@@ -266,6 +267,9 @@ export class NormalizeOption {
266267
...(this.options.outputEntry ? { entryFilename: this.options.outputEntry.name } : {}),
267268
path: this.options.outputDir,
268269
},
270+
// TODO: fix in script mode, resources are now only synchronized once at startup
271+
// and lazyCompilation cannot obtain the latest resources in a timely manner.
272+
...(this.options.execute.type === ExecuteMode.Node ? { lazyCompilation: true } : {}),
269273
...pick(this.options, 'minify', 'sourcemap', 'external'),
270274
},
271275
},

packages/core/src/core/ipc/client.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,35 @@ export class IpcClient<S, R> {
99
start(socketPath: string) {
1010
const client = net.createConnection(socketPath);
1111

12-
client.on('data', (data) => {
13-
this.events.emit('data', data);
12+
let data = Buffer.alloc(0);
13+
14+
client.on('end', () => {
15+
this.events.emit('data', data.toString('utf-8'));
16+
data = Buffer.alloc(0);
17+
});
18+
19+
client.on('data', (buffer) => {
20+
data = Buffer.concat([new Uint8Array(data), new Uint8Array(buffer)], data.byteLength + buffer.byteLength);
1421
});
1522

1623
this.client = client;
1724
}
1825

19-
send(data: S) {
20-
this.client.write(JSON.stringify(data));
26+
async send(data: S) {
27+
return new Promise<void>((resolve) => {
28+
this.client.end(JSON.stringify(data), () => {
29+
resolve();
30+
});
31+
});
2132
}
2233

2334
onMessage(callback: (data: R) => void) {
2435
this.events.on('data', (data) => {
2536
callback(JSON.parse(data.toString()));
2637
});
2738
}
39+
40+
close() {
41+
this.client.end();
42+
}
2843
}

packages/core/src/core/ipc/server.ts

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ export class IpcServer<S, R> {
5757

5858
close() {
5959
this._server.close();
60+
for (const socket of this.sockets) {
61+
socket.close();
62+
}
6063
this.sockets.clear();
6164
}
6265

0 commit comments

Comments
 (0)