Add support for .mjs, .mts, .cjs, and .cts file extensions in the SWC transform (#556)

- Updated turbopack rules to include `*.mjs`, `*.mts`, `*.cjs`, `*.cts` in addition to existing extensions
- Fixed TypeScript detection for `.mts` and `.cts` files across all transform plugins
- Updated esbuild `resolveExtensions` to include `.mts` and `.cts`
- Updated the file watcher's `watchableExtensions` to include `.cts`
This commit is contained in:
Nathan Rajlich
2025-12-05 14:39:10 -08:00
committed by GitHub
parent af5b005ac8
commit 21cff154a3
9 changed files with 95 additions and 11 deletions
+12
View File
@@ -0,0 +1,12 @@
---
"@workflow/next": patch
"@workflow/builders": patch
"@workflow/rollup": patch
---
Add support for `.mjs`, `.mts`, `.cjs`, and `.cts` file extensions in the SWC transform
- Updated turbopack rules to include `*.mjs`, `*.mts`, `*.cjs`, `*.cts` in addition to existing extensions
- Fixed TypeScript detection for `.mts` and `.cts` files across all transform plugins
- Updated esbuild `resolveExtensions` to include `.mts` and `.cts`
- Updated the file watcher's `watchableExtensions` to include `.cts`
+5 -1
View File
@@ -34,7 +34,11 @@ export async function applySwcTransform(
workflowManifest: WorkflowManifest;
}> {
// Determine if this is a TypeScript file
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx');
const isTypeScript =
filename.endsWith('.ts') ||
filename.endsWith('.tsx') ||
filename.endsWith('.mts') ||
filename.endsWith('.cts');
// Transform with SWC to support syntax esbuild doesn't
const result = await transform(source, {
+40 -4
View File
@@ -366,7 +366,16 @@ export abstract class BaseBuilder {
keepNames: true,
minify: false,
jsx: 'preserve',
resolveExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
resolveExtensions: [
'.ts',
'.tsx',
'.mts',
'.cts',
'.js',
'.jsx',
'.mjs',
'.cjs',
],
// TODO: investigate proper source map support
sourcemap: EMIT_SOURCEMAPS_FOR_DEBUGGING,
plugins: [
@@ -498,7 +507,16 @@ export abstract class BaseBuilder {
// This intermediate bundle is executed via runInContext() in a VM, so we need
// inline source maps to get meaningful stack traces instead of "evalmachine.<anonymous>".
sourcemap: 'inline',
resolveExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
resolveExtensions: [
'.ts',
'.tsx',
'.mts',
'.cts',
'.js',
'.jsx',
'.mjs',
'.cjs',
],
plugins: [
createSwcPlugin({
mode: 'workflow',
@@ -680,7 +698,16 @@ export const POST = workflowEntrypoint(workflowCode);`;
write: true,
treeShaking: true,
external: ['@workflow/core'],
resolveExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
resolveExtensions: [
'.ts',
'.tsx',
'.mts',
'.cts',
'.js',
'.jsx',
'.mjs',
'.cjs',
],
plugins: [createSwcPlugin({ mode: 'client' })],
});
@@ -768,7 +795,16 @@ export const OPTIONS = handler;`;
treeShaking: true,
keepNames: true,
minify: false,
resolveExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
resolveExtensions: [
'.ts',
'.tsx',
'.mts',
'.cts',
'.js',
'.jsx',
'.mjs',
'.cjs',
],
sourcemap: false,
mainFields: ['module', 'main'],
// Don't externalize anything - bundle everything including workflow packages
@@ -6,7 +6,7 @@ import { applySwcTransform } from './apply-swc-transform.js';
const enhancedResolve = promisify(enhancedResolveOriginal);
export const jsTsRegex = /\.(ts|tsx|js|jsx|mjs|cjs)$/;
export const jsTsRegex = /\.(ts|tsx|js|jsx|mjs|cjs|mts|cts)$/;
// Matches: 'use workflow'; "use workflow"; 'use step'; "use step"; at line start with optional whitespace
export const useWorkflowPattern = /^\s*(['"])use workflow\1;?\s*$/m;
@@ -66,7 +66,10 @@ export function createDiscoverEntriesPlugin(state: {
// Determine the loader based on the output
let loader: 'js' | 'jsx' = 'js';
const isTypeScript =
args.path.endsWith('.ts') || args.path.endsWith('.tsx');
args.path.endsWith('.ts') ||
args.path.endsWith('.tsx') ||
args.path.endsWith('.mts') ||
args.path.endsWith('.cts');
if (!isTypeScript && args.path.endsWith('.jsx')) {
loader = 'jsx';
}
+12 -1
View File
@@ -28,7 +28,18 @@ const NODE_RESOLVE_OPTIONS = {
importsFields: ['imports'],
conditionNames: ['node', 'require'],
descriptionFiles: ['package.json'],
extensions: ['.ts', '.mts', '.cjs', '.js', '.json', '.node'],
extensions: [
'.ts',
'.tsx',
'.mts',
'.cts',
'.cjs',
'.mjs',
'.js',
'.jsx',
'.json',
'.node',
],
enforceExtensions: false,
symlinks: true,
mainFields: ['main'],
+1
View File
@@ -76,6 +76,7 @@ export async function getNextBuilder() {
'.ts',
'.tsx',
'.mts',
'.cts',
'.cjs',
'.mjs',
]);
+10 -1
View File
@@ -62,7 +62,16 @@ export function withWorkflow(
const nextVersion = require('next/package.json').version;
const supportsTurboCondition = semver.gte(nextVersion, 'v16.0.0');
for (const key of ['*.tsx', '*.ts', '*.jsx', '*.js']) {
for (const key of [
'*.tsx',
'*.ts',
'*.jsx',
'*.js',
'*.mjs',
'*.mts',
'*.cjs',
'*.cts',
]) {
nextConfig.turbopack.rules[key] = {
...(supportsTurboCondition
? {
+5 -1
View File
@@ -18,7 +18,11 @@ export default async function workflowLoader(
return normalizedSource;
}
const isTypeScript = filename.endsWith('.ts') || filename.endsWith('.tsx');
const isTypeScript =
filename.endsWith('.ts') ||
filename.endsWith('.tsx') ||
filename.endsWith('.mts') ||
filename.endsWith('.cts');
// Calculate relative filename for SWC plugin
// The SWC plugin uses filename to generate workflowId, so it must be relative
+5 -1
View File
@@ -14,7 +14,11 @@ export function workflowTransformPlugin(): Plugin {
return null;
}
const isTypeScript = id.endsWith('.ts') || id.endsWith('.tsx');
const isTypeScript =
id.endsWith('.ts') ||
id.endsWith('.tsx') ||
id.endsWith('.mts') ||
id.endsWith('.cts');
const swcPlugin = resolveModulePath('@workflow/swc-plugin', {
from: [import.meta.url],