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

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,202 @@
1
+ import path from 'node:path'
2
+ import {optimizeLodashImports} from '@optimize-lodash/rollup-plugin'
3
+ import alias from '@rollup/plugin-alias'
4
+ import {getBabelOutputPlugin} from '@rollup/plugin-babel'
5
+ import commonjs from '@rollup/plugin-commonjs'
6
+ import json from '@rollup/plugin-json'
7
+ import {nodeResolve} from '@rollup/plugin-node-resolve'
8
+ import terser from '@rollup/plugin-terser'
9
+ import type {InputOptions, OutputOptions, Plugin} from 'rolldown'
10
+ import {dts as dtsPlugin} from 'rolldown-plugin-dts'
11
+ import esbuild from 'rollup-plugin-esbuild'
12
+ import type {BuildContext} from '../../core/contexts/buildContext'
13
+ import {pkgExtMap as extMap} from '../../core/pkg/pkgExt'
14
+ import type {PackageJSON} from '../../core/pkg/types'
15
+ import type {RolldownDtsTask} from '../types'
16
+
17
+ export interface RolldownConfig {
18
+ inputOptions: InputOptions
19
+ outputOptions: OutputOptions
20
+ }
21
+
22
+ export function resolveRolldownConfig(
23
+ ctx: BuildContext,
24
+ buildTask: RolldownDtsTask,
25
+ ): RolldownConfig {
26
+ const {format, runtime, target} = buildTask
27
+ const {config, cwd, exports: _exports, external, distPath, logger, pkg, ts} = ctx
28
+ const outputExt = extMap[pkg.type || 'commonjs'][format]
29
+ const minify = config?.minify ?? false
30
+ const outDir = path.relative(cwd, distPath)
31
+
32
+ const pathAliases = Object.fromEntries(
33
+ Object.entries(ts.config?.options.paths || {}).map(([key, val]) => {
34
+ return [key, path.resolve(cwd, ts.config?.options.baseUrl || '.', val[0])]
35
+ }),
36
+ )
37
+
38
+ const entries = buildTask.entries.map((entry) => {
39
+ return {
40
+ ...entry,
41
+ name: path.relative(outDir, entry.output).replace(/\.[^/.]+$/, ''),
42
+ }
43
+ }, {})
44
+
45
+ const exportIds =
46
+ _exports && Object.keys(_exports).map((exportPath) => path.join(pkg.name, exportPath))
47
+
48
+ const sourcePaths = _exports && Object.values(_exports).map((e) => path.resolve(cwd, e.source))
49
+
50
+ const replacements = Object.fromEntries(
51
+ Object.entries(config?.define || {}).map(([key, val]) => [key, JSON.stringify(val)]),
52
+ )
53
+
54
+ const {optimizeLodash: enableOptimizeLodash = hasDependency(pkg, 'lodash')} = config?.rollup || {}
55
+
56
+ // @ts-expect-error - TODO: fix this
57
+ const _defaultPlugins = [
58
+ alias({
59
+ entries: {...pathAliases},
60
+ }),
61
+ nodeResolve({
62
+ browser: runtime === 'browser',
63
+ extensions: ['.cjs', '.mjs', '.js', '.jsx', '.json', '.node'],
64
+ preferBuiltins: true,
65
+ }),
66
+ commonjs(),
67
+ json(),
68
+ esbuild({
69
+ target,
70
+ tsconfig: ctx.ts.configPath || 'tsconfig.json',
71
+ treeShaking: true,
72
+ minifySyntax: config?.minify !== false,
73
+ supported: {
74
+ 'template-literal': true,
75
+ },
76
+ }),
77
+ Array.isArray(config?.babel?.plugins) &&
78
+ getBabelOutputPlugin({
79
+ babelrc: false,
80
+ plugins: config.babel.plugins,
81
+ }),
82
+ enableOptimizeLodash &&
83
+ optimizeLodashImports({
84
+ useLodashEs: format === 'esm' && hasDependency(pkg, 'lodash-es') ? true : undefined,
85
+ ...(typeof config?.rollup?.optimizeLodash === 'boolean'
86
+ ? {}
87
+ : config?.rollup?.optimizeLodash),
88
+ }),
89
+ minify &&
90
+ terser({
91
+ compress: {directives: false, passes: 10},
92
+ ecma: 2020,
93
+ output: {
94
+ comments: (_node, comment) => {
95
+ const text = comment.value
96
+ const cType = comment.type
97
+
98
+ // Check if this is a multiline comment
99
+ if (cType === 'comment2') {
100
+ // Keep licensing comments
101
+ return /@preserve|@license|@cc_on/i.test(text)
102
+ }
103
+
104
+ return false
105
+ },
106
+ preserve_annotations: true,
107
+ },
108
+ }),
109
+ ].filter(Boolean) as Plugin[]
110
+
111
+ const hashChunkFileNames = config?.rollup?.hashChunkFileNames ?? false
112
+ const chunksFolder = hashChunkFileNames ? '_chunks' : '_chunks-[format]'
113
+ const chunkFileNames = `${chunksFolder}/${hashChunkFileNames ? '[name]-[hash]' : '[name]'}${outputExt}`
114
+ const entryFileNames = `[name]${outputExt}`
115
+
116
+ const inputOptions = {
117
+ cwd,
118
+ jsx: {
119
+ mode:
120
+ config?.jsx === 'automatic'
121
+ ? 'automatic'
122
+ : config?.jsx === 'preserve'
123
+ ? 'preserve'
124
+ : config?.jsx === 'transform'
125
+ ? 'classic'
126
+ : 'automatic',
127
+ factory: config?.jsxFactory,
128
+ fragment: config?.jsxFragment,
129
+ importSource: config?.jsxImportSource,
130
+ },
131
+ define:
132
+ pkg.name === '@sanity/pkg-utils'
133
+ ? {...replacements}
134
+ : {
135
+ 'process.env.PKG_FORMAT': JSON.stringify(format),
136
+ 'process.env.PKG_RUNTIME': JSON.stringify(runtime),
137
+ 'process.env.PKG_VERSION': JSON.stringify(process.env['PKG_VERSION'] || pkg.version),
138
+ ...replacements,
139
+ },
140
+
141
+ external: (id, importer) => {
142
+ // Check if the id is a self-referencing import
143
+ if (exportIds?.includes(id)) {
144
+ return true
145
+ }
146
+
147
+ // Check if the id is a file path that points to an exported source file
148
+ if (importer && (id.startsWith('.') || id.startsWith('/'))) {
149
+ const idPath = path.resolve(path.dirname(importer), id)
150
+
151
+ if (sourcePaths?.includes(idPath)) {
152
+ logger.warn(
153
+ `detected self-referencing import – treating as external: ${path.relative(
154
+ cwd,
155
+ idPath,
156
+ )}`,
157
+ )
158
+
159
+ return true
160
+ }
161
+ }
162
+
163
+ const idParts = id.split('/')
164
+
165
+ const name = idParts[0].startsWith('@') ? `${idParts[0]}/${idParts[1]}` : idParts[0]
166
+
167
+ if (name && external.includes(name)) {
168
+ return true
169
+ }
170
+
171
+ return false
172
+ },
173
+
174
+ input: entries.reduce<{[entryAlias: string]: string}>(
175
+ (acc, entry) => Object.assign(acc, {[entry.name]: entry.source}),
176
+ {},
177
+ ),
178
+
179
+ plugins: [dtsPlugin({emitDtsOnly: true, tsconfig: ctx.ts.configPath || 'tsconfig.json'})],
180
+
181
+ treeshake: true,
182
+ } satisfies InputOptions
183
+ const outputOptions = {
184
+ chunkFileNames,
185
+ dir: outDir,
186
+ entryFileNames,
187
+ esModule: true,
188
+ format: buildTask.type === 'rolldown:dts' ? 'es' : format,
189
+ sourcemap: buildTask.type === 'rolldown:dts' ? false : (config?.sourcemap ?? true),
190
+ hoistTransitiveImports: false,
191
+ } satisfies OutputOptions
192
+
193
+ return {inputOptions, outputOptions}
194
+ }
195
+
196
+ function hasDependency(pkg: PackageJSON, packageName: string): boolean {
197
+ return pkg.dependencies
198
+ ? packageName in pkg.dependencies
199
+ : pkg.peerDependencies
200
+ ? packageName in pkg.peerDependencies
201
+ : false
202
+ }
@@ -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 */