@sanity/pkg-utils 7.2.9 → 7.2.10-canary.1

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.
@@ -0,0 +1,208 @@
1
+ import path from 'node:path'
2
+ import {optimizeLodashImports} from '@optimize-lodash/rollup-plugin'
3
+ import {getBabelOutputPlugin} from '@rollup/plugin-babel'
4
+ import terser from '@rollup/plugin-terser'
5
+ import type {InputOptions, OutputOptions, Plugin} from 'rolldown'
6
+ import {dts as dtsPlugin} from 'rolldown-plugin-dts'
7
+ import esbuild from 'rollup-plugin-esbuild'
8
+ import type {BuildContext} from '../../core/contexts/buildContext'
9
+ import {pkgExtMap as extMap} from '../../core/pkg/pkgExt'
10
+ import type {PackageJSON} from '../../core/pkg/types'
11
+ import type {RolldownDtsTask} from '../types'
12
+
13
+ export interface RolldownConfig {
14
+ inputOptions: InputOptions
15
+ outputOptions: OutputOptions
16
+ }
17
+
18
+ export function resolveRolldownConfig(
19
+ ctx: BuildContext,
20
+ buildTask: RolldownDtsTask,
21
+ ): RolldownConfig {
22
+ const {format, runtime, target} = buildTask
23
+ const {config, cwd, exports: _exports, external, distPath, logger, pkg, ts} = ctx
24
+ const outputExt = extMap[pkg.type || 'commonjs'][format]
25
+ const minify = config?.minify ?? false
26
+ const outDir = path.relative(cwd, distPath)
27
+
28
+ const pathAliases = Object.fromEntries(
29
+ Object.entries(ts.config?.options.paths || {}).map(([key, val]) => {
30
+ return [key, path.resolve(cwd, ts.config?.options.baseUrl || '.', val[0])]
31
+ }),
32
+ )
33
+
34
+ const entries = buildTask.entries.map((entry) => {
35
+ return {
36
+ ...entry,
37
+ name: path.relative(outDir, entry.output).replace(/\.[^/.]+$/, ''),
38
+ }
39
+ }, {})
40
+
41
+ const exportIds =
42
+ _exports && Object.keys(_exports).map((exportPath) => path.join(pkg.name, exportPath))
43
+
44
+ const sourcePaths = _exports && Object.values(_exports).map((e) => path.resolve(cwd, e.source))
45
+
46
+ const replacements = Object.fromEntries(
47
+ Object.entries(config?.define || {}).map(([key, val]) => [key, JSON.stringify(val)]),
48
+ )
49
+
50
+ const {optimizeLodash: enableOptimizeLodash = hasDependency(pkg, 'lodash')} = config?.rollup || {}
51
+
52
+ // @ts-expect-error - TODO: fix this
53
+ const _defaultPlugins = [
54
+ esbuild({
55
+ target,
56
+ tsconfig: ctx.ts.configPath || 'tsconfig.json',
57
+ treeShaking: true,
58
+ minifySyntax: config?.minify !== false,
59
+ supported: {
60
+ 'template-literal': true,
61
+ },
62
+ }),
63
+ Array.isArray(config?.babel?.plugins) &&
64
+ getBabelOutputPlugin({
65
+ babelrc: false,
66
+ plugins: config.babel.plugins,
67
+ }),
68
+ enableOptimizeLodash &&
69
+ optimizeLodashImports({
70
+ useLodashEs: format === 'esm' && hasDependency(pkg, 'lodash-es') ? true : undefined,
71
+ ...(typeof config?.rollup?.optimizeLodash === 'boolean'
72
+ ? {}
73
+ : config?.rollup?.optimizeLodash),
74
+ }),
75
+ minify &&
76
+ terser({
77
+ compress: {directives: false, passes: 10},
78
+ ecma: 2020,
79
+ output: {
80
+ comments: (_node, comment) => {
81
+ const text = comment.value
82
+ const cType = comment.type
83
+
84
+ // Check if this is a multiline comment
85
+ if (cType === 'comment2') {
86
+ // Keep licensing comments
87
+ return /@preserve|@license|@cc_on/i.test(text)
88
+ }
89
+
90
+ return false
91
+ },
92
+ preserve_annotations: true,
93
+ },
94
+ }),
95
+ ].filter(Boolean) as Plugin[]
96
+
97
+ const hashChunkFileNames = config?.rollup?.hashChunkFileNames ?? false
98
+ const chunksFolder = hashChunkFileNames ? '_chunks' : '_chunks-[format]'
99
+ const chunkFileNames = `${chunksFolder}/${hashChunkFileNames ? '[name]-[hash]' : '[name]'}${outputExt}`
100
+ const entryFileNames = `[name]${outputExt}`
101
+
102
+ const inputOptions = {
103
+ cwd,
104
+ jsx: {
105
+ mode:
106
+ config?.jsx === 'automatic'
107
+ ? 'automatic'
108
+ : config?.jsx === 'preserve'
109
+ ? 'preserve'
110
+ : config?.jsx === 'transform'
111
+ ? 'classic'
112
+ : 'automatic',
113
+ factory: config?.jsxFactory,
114
+ fragment: config?.jsxFragment,
115
+ importSource: config?.jsxImportSource,
116
+ },
117
+ define:
118
+ pkg.name === '@sanity/pkg-utils'
119
+ ? {...replacements}
120
+ : {
121
+ 'process.env.PKG_FORMAT': JSON.stringify(format),
122
+ 'process.env.PKG_RUNTIME': JSON.stringify(runtime),
123
+ 'process.env.PKG_VERSION': JSON.stringify(process.env['PKG_VERSION'] || pkg.version),
124
+ ...replacements,
125
+ },
126
+
127
+ platform:
128
+ buildTask.type === 'rolldown:dts'
129
+ ? 'node'
130
+ : runtime === 'node'
131
+ ? 'node'
132
+ : runtime === 'browser'
133
+ ? 'browser'
134
+ : 'neutral',
135
+
136
+ resolve: {
137
+ alias: pathAliases,
138
+ tsconfigFilename: ctx.ts.configPath || 'tsconfig.json',
139
+ },
140
+ transform: {
141
+ target,
142
+ },
143
+ experimental: {
144
+ attachDebugInfo: 'none',
145
+ },
146
+
147
+ external: (id, importer) => {
148
+ // Check if the id is a self-referencing import
149
+ if (exportIds?.includes(id)) {
150
+ return true
151
+ }
152
+
153
+ // Check if the id is a file path that points to an exported source file
154
+ if (importer && (id.startsWith('.') || id.startsWith('/'))) {
155
+ const idPath = path.resolve(path.dirname(importer), id)
156
+
157
+ if (sourcePaths?.includes(idPath)) {
158
+ logger.warn(
159
+ `detected self-referencing import – treating as external: ${path.relative(
160
+ cwd,
161
+ idPath,
162
+ )}`,
163
+ )
164
+
165
+ return true
166
+ }
167
+ }
168
+
169
+ const idParts = id.split('/')
170
+
171
+ const name = idParts[0].startsWith('@') ? `${idParts[0]}/${idParts[1]}` : idParts[0]
172
+
173
+ if (name && external.includes(name)) {
174
+ return true
175
+ }
176
+
177
+ return false
178
+ },
179
+
180
+ input: entries.reduce<{[entryAlias: string]: string}>(
181
+ (acc, entry) => Object.assign(acc, {[entry.name]: entry.source}),
182
+ {},
183
+ ),
184
+
185
+ plugins: [dtsPlugin({emitDtsOnly: true, tsconfig: ctx.ts.configPath || 'tsconfig.json'})],
186
+
187
+ treeshake: true,
188
+ } satisfies InputOptions
189
+ const outputOptions = {
190
+ chunkFileNames,
191
+ dir: outDir,
192
+ entryFileNames,
193
+ esModule: true,
194
+ format: buildTask.type === 'rolldown:dts' ? 'es' : format,
195
+ sourcemap: buildTask.type === 'rolldown:dts' ? false : (config?.sourcemap ?? true),
196
+ hoistTransitiveImports: false,
197
+ } satisfies OutputOptions
198
+
199
+ return {inputOptions, outputOptions}
200
+ }
201
+
202
+ function hasDependency(pkg: PackageJSON, packageName: string): boolean {
203
+ return pkg.dependencies
204
+ ? packageName in pkg.dependencies
205
+ : pkg.peerDependencies
206
+ ? packageName in pkg.peerDependencies
207
+ : false
208
+ }
@@ -0,0 +1,155 @@
1
+ import path from 'node:path'
2
+ import chalk from 'chalk'
3
+ import {rolldown} from 'rolldown'
4
+ import {from} from 'rxjs'
5
+ import {createConsoleSpy} from '../../consoleSpy'
6
+ import type {BuildContext} from '../../core/contexts/buildContext'
7
+ import type {RolldownDtsTask, TaskHandler} from '../types'
8
+ import {resolveRolldownConfig} from './resolveRolldownConfig'
9
+
10
+ /** @internal */
11
+ export const rolldownDtsTask: TaskHandler<RolldownDtsTask> = {
12
+ name: (ctx, task) => {
13
+ const bundleEntries = task.entries.filter((e) => e.path.includes('__$$bundle_'))
14
+ const entries = task.entries.filter((e) => !e.path.includes('__$$bundle_'))
15
+
16
+ const targetLines = task.target.length
17
+ ? [` target:`, ...task.target.map((t) => ` - ${chalk.yellow(t)}`)]
18
+ : []
19
+
20
+ const bundlesLines = bundleEntries.length
21
+ ? [
22
+ ' bundles:',
23
+ ...bundleEntries.map((e) =>
24
+ [
25
+ ` - `,
26
+ `${chalk.yellow(e.source)} ${chalk.gray('→')} ${chalk.yellow(e.output)}`,
27
+ ].join(''),
28
+ ),
29
+ ]
30
+ : []
31
+
32
+ const entriesLines = entries.length
33
+ ? [
34
+ ' entries:',
35
+ ...entries.map((e) =>
36
+ [
37
+ ` - `,
38
+ `${chalk.cyan(path.join(ctx.pkg.name, e.path))}: `,
39
+ `${chalk.yellow(e.source)} ${chalk.gray('→')} ${chalk.yellow(e.output)}`,
40
+ ].join(''),
41
+ ),
42
+ ]
43
+ : []
44
+
45
+ return [
46
+ `Build type definitions with ${chalk.bold('rolldown')}...`,
47
+ ` format: ${chalk.yellow(task.format)}`,
48
+ ...targetLines,
49
+ ...bundlesLines,
50
+ ...entriesLines,
51
+ ].join('\n')
52
+ },
53
+ exec: (ctx, task) => {
54
+ return from(execPromise(ctx, task))
55
+ // return new Observable((observer) => {
56
+ // execPromise(ctx, task)
57
+ // .then((result) => {
58
+ // observer.next(result)
59
+ // observer.complete()
60
+ // })
61
+ // .catch((err) => observer.error(err))
62
+ // })
63
+ },
64
+ complete: () => {
65
+ //
66
+ },
67
+ error: (_ctx, _task, err) => {
68
+ console.error(err)
69
+ },
70
+ }
71
+
72
+ async function execPromise(ctx: BuildContext, task: RolldownDtsTask) {
73
+ const {distPath, files, logger} = ctx
74
+ const outDir = path.relative(ctx.cwd, distPath)
75
+
76
+ // Prevent rolldown from printing directly to the console
77
+ const consoleSpy = createConsoleSpy({
78
+ onRestored: (messages) => {
79
+ for (const msg of messages) {
80
+ const text = String(msg.args[0])
81
+
82
+ if (msg.code === 'CIRCULAR_DEPENDENCY') {
83
+ continue // ignore
84
+ }
85
+
86
+ if (text.startsWith('Dynamic import can only')) {
87
+ continue // ignore
88
+ }
89
+
90
+ if (text.startsWith('Sourcemap is likely to be incorrect')) {
91
+ continue // ignore
92
+ }
93
+
94
+ if (msg.type === 'log') {
95
+ logger.info(...msg.args)
96
+ }
97
+
98
+ if (msg.type === 'warn') {
99
+ logger.warn(...msg.args)
100
+ }
101
+
102
+ if (msg.type === 'error') {
103
+ logger.error(...msg.args)
104
+ }
105
+ }
106
+ },
107
+ })
108
+
109
+ try {
110
+ const {inputOptions, outputOptions} = resolveRolldownConfig(ctx, task)
111
+
112
+ // Create bundle
113
+ const bundle = await rolldown({
114
+ ...inputOptions,
115
+ onwarn(warning) {
116
+ consoleSpy.messages.push({
117
+ type: 'warn',
118
+ code: warning.code,
119
+ args: [warning.message],
120
+ })
121
+ },
122
+ })
123
+
124
+ // generate output specific code in-memory
125
+ // you can call this function multiple times on the same bundle object
126
+ const {output} = await bundle.generate(outputOptions)
127
+
128
+ for (const chunkOrAsset of output) {
129
+ if (chunkOrAsset.type === 'asset') {
130
+ files.push({
131
+ type: 'asset',
132
+ path: path.resolve(outDir, chunkOrAsset.fileName),
133
+ })
134
+ } else {
135
+ files.push({
136
+ type: 'chunk',
137
+ path: path.resolve(outDir, chunkOrAsset.fileName),
138
+ })
139
+ }
140
+ }
141
+
142
+ // or write the bundle to disk
143
+ await bundle.write(outputOptions)
144
+
145
+ // closes the bundle
146
+ await bundle.close()
147
+
148
+ // Restore console
149
+ consoleSpy.restore()
150
+ } catch (err) {
151
+ // Restore console
152
+ consoleSpy.restore()
153
+ throw err
154
+ }
155
+ }
@@ -21,6 +21,16 @@ export interface RollupTask {
21
21
  target: string[]
22
22
  }
23
23
 
24
+ /** @internal */
25
+ export interface RolldownDtsTask {
26
+ type: 'rolldown:dts'
27
+ buildId: string
28
+ entries: RollupTaskEntry[]
29
+ runtime: PkgRuntime
30
+ format: 'commonjs' | 'esm'
31
+ target: string[]
32
+ }
33
+
24
34
  /** @internal */
25
35
  export interface RollupWatchTask {
26
36
  type: 'watch:js'
@@ -32,7 +42,7 @@ export interface RollupWatchTask {
32
42
  }
33
43
 
34
44
  /** @internal */
35
- export type BuildTask = DtsTask | RollupTask
45
+ export type BuildTask = DtsTask | RollupTask | RolldownDtsTask
36
46
 
37
47
  /** @internal */
38
48
  export type WatchTask = DtsWatchTask | RollupWatchTask
@@ -49,6 +59,7 @@ export type TaskHandler<Task, Result = void> = {
49
59
  export interface BuildTaskHandlers {
50
60
  'build:dts': TaskHandler<DtsTask, DtsResult>
51
61
  'build:js': TaskHandler<RollupTask>
62
+ 'rolldown:dts': TaskHandler<RolldownDtsTask>
52
63
  }
53
64
 
54
65
  /** @internal */