Skip to content

Commit f5b9826

Browse files
committed
Fix a relative ordering issue where a configuration could override a with attribute and add a test
1 parent 0988c2a commit f5b9826

5 files changed

Lines changed: 50 additions & 29 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
throw new Error('this file is configured as ecmascript but imported as bytes')

test/e2e/turbopack-import-with-type/app/api/route.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import text from './data.txt' with { type: 'text' }
22
import jsAsText from './some.js' with { type: 'text' }
33
import bytes from './data.bin' with { type: 'bytes' }
44
import jsAsBytes from './some.js' with { type: 'bytes' }
5+
import configuredAsJsAsBytes from './configured-as-ecmascript.txt' with { type: 'bytes' }
56

67
export async function GET(_req) {
78
return Response.json(
@@ -24,6 +25,10 @@ export async function GET(_req) {
2425
instanceofUint8Array: jsAsBytes instanceof Uint8Array,
2526
content: new TextDecoder().decode(jsAsBytes),
2627
},
28+
configuredAsJsAsBytes: {
29+
instanceofUint8Array: configuredAsJsAsBytes instanceof Uint8Array,
30+
content: new TextDecoder().decode(configuredAsJsAsBytes),
31+
},
2732
},
2833
{ status: 200 }
2934
)

test/e2e/turbopack-import-with-type/index.test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ describe('turbopack-import-with-type', () => {
3737
instanceofUint8Array: true,
3838
content: jsContent,
3939
},
40+
configuredAsJsAsBytes: {
41+
instanceofUint8Array: true,
42+
content:
43+
"throw new Error('this file is configured as ecmascript but imported as bytes')\n",
44+
},
4045
})
4146
})
4247
})
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
1-
export default {
1+
import type { NextConfig } from 'next'
2+
3+
const config: NextConfig = {
24
experimental: {
35
turbopackImportTypeBytes: true,
46
turbopackImportTypeText: true,
57
},
8+
turbopack: {
9+
rules: {
10+
// This rule configures a .txt file as ecmascript to test that
11+
// import attributes (with { type: 'bytes' }) take priority
12+
'**/configured-as-ecmascript.txt': {
13+
type: 'ecmascript',
14+
},
15+
},
16+
},
617
}
18+
19+
export default config

turbopack/crates/turbopack/src/module_options/mod.rs

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,31 @@ impl ModuleOptions {
361361

362362
let mut rules = vec![];
363363

364+
// Import attribute rules (bytes/text) must come BEFORE config rules.
365+
// Import attributes have a stronger API contract - they're explicit in the source code
366+
// and should override any file-pattern-based config rules.
367+
if enable_import_as_bytes {
368+
rules.push(ModuleRule::new(
369+
RuleCondition::ReferenceType(ReferenceType::EcmaScriptModules(
370+
EcmaScriptModulesReferenceSubType::ImportWithType("bytes".into()),
371+
)),
372+
vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
373+
ResolvedVc::upcast(BytesSourceTransform::new().to_resolved().await?),
374+
]))],
375+
));
376+
}
377+
378+
if enable_import_as_text {
379+
rules.push(ModuleRule::new(
380+
RuleCondition::ReferenceType(ReferenceType::EcmaScriptModules(
381+
EcmaScriptModulesReferenceSubType::ImportWithType("text".into()),
382+
)),
383+
vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
384+
ResolvedVc::upcast(TextSourceTransform::new().to_resolved().await?),
385+
]))],
386+
));
387+
}
388+
364389
if let Some(webpack_loaders_options) = enable_webpack_loaders {
365390
let webpack_loaders_options = webpack_loaders_options.await?;
366391
let execution_context =
@@ -531,34 +556,6 @@ impl ModuleOptions {
531556
),
532557
]);
533558

534-
if enable_import_as_bytes {
535-
// Rule to apply the source transform when importing with type:"bytes".
536-
// The transform renames the file to .mjs, so the existing .mjs rule will
537-
// set the module type to Ecmascript.
538-
rules.push(ModuleRule::new(
539-
RuleCondition::ReferenceType(ReferenceType::EcmaScriptModules(
540-
EcmaScriptModulesReferenceSubType::ImportWithType("bytes".into()),
541-
)),
542-
vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
543-
ResolvedVc::upcast(BytesSourceTransform::new().to_resolved().await?),
544-
]))],
545-
));
546-
}
547-
548-
if enable_import_as_text {
549-
// Rule to apply the source transform when importing with type:"text".
550-
// The transform renames the file to .mjs, so the existing .mjs rule will
551-
// set the module type to Ecmascript.
552-
rules.push(ModuleRule::new(
553-
RuleCondition::ReferenceType(ReferenceType::EcmaScriptModules(
554-
EcmaScriptModulesReferenceSubType::ImportWithType("text".into()),
555-
)),
556-
vec![ModuleRuleEffect::SourceTransforms(ResolvedVc::cell(vec![
557-
ResolvedVc::upcast(TextSourceTransform::new().to_resolved().await?),
558-
]))],
559-
));
560-
}
561-
562559
// Rules that apply based on file extension or content type
563560
rules.extend([
564561
ModuleRule::new_all(

0 commit comments

Comments
 (0)