Skip to content

Commit

Permalink
Add support for custom targets from CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcompiles committed Dec 19, 2024
1 parent 5d49c16 commit 45a90ae
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 112 deletions.
92 changes: 70 additions & 22 deletions crates/atlaspack/src/requests/target_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,19 @@ use atlaspack_core::types::Environment;
use atlaspack_core::types::EnvironmentContext;
use atlaspack_core::types::ErrorKind;
use atlaspack_core::types::OutputFormat;
use atlaspack_core::types::SourceField;
use atlaspack_core::types::SourceMapField;
use atlaspack_core::types::SourceType;
use atlaspack_core::types::Target;
use atlaspack_core::types::TargetDescriptor;
use atlaspack_core::types::TargetSourceMapOptions;
use atlaspack_core::types::Targets;
use atlaspack_resolver::IncludeNodeModules;
use package_json::BrowserField;
use package_json::BrowsersList;
use package_json::BuiltInTargetDescriptor;
use package_json::ModuleFormat;
use package_json::PackageJson;
use package_json::SourceField;
use package_json::SourceMapField;
use package_json::TargetDescriptor;

use crate::request_tracker::Request;
use crate::request_tracker::ResultAndInvalidations;
Expand Down Expand Up @@ -339,6 +340,24 @@ impl TargetRequest {
),
];

let mut target_filter = None;

if let Some(target_options) = &request_context.options.targets {
match target_options {
Targets::Filter(target_list) => {
target_filter = Some(target_list);
}
Targets::CustomTarget(custom_targets) => {
for (name, descriptor) in custom_targets.iter() {
targets.push(self.target_from_descriptor(None, &config, descriptor.clone(), name)?);
}

// Custom targets have been passed in so let's just use those
return Ok(targets);
}
}
}

for builtin_target in builtin_targets {
if builtin_target.dist.is_none() {
continue;
Expand All @@ -362,26 +381,14 @@ impl TargetRequest {
.targets
.custom_targets
.iter()
.map(|(name, descriptor)| CustomTarget { descriptor, name });
.map(|(name, descriptor)| CustomTarget { descriptor, name })
.filter(|CustomTarget { name, .. }| {
target_filter
.as_ref()
.is_none_or(|targets| targets.iter().any(|target_name| target_name == name))
});

for custom_target in custom_targets {
if request_context
.options
.targets
.as_ref()
.is_some_and(|targets| {
!targets
.iter()
.any(|target_name| target_name == custom_target.name)
})
{
tracing::debug!(
"Skipping custom target {} as it doesn't match passed in target options",
custom_target.name
);
continue;
}

let mut dist = None;
if let Some(value) = config.contents.fields.get(custom_target.name) {
match value {
Expand Down Expand Up @@ -1406,6 +1413,47 @@ mod tests {
);
}

#[tokio::test(flavor = "multi_thread")]
async fn returns_custom_targets_from_options_with_defaults() {
let targets = targets_from_config(
String::from(r#"{}"#),
None,
Some(AtlaspackOptions {
targets: Some(Targets::CustomTarget(BTreeMap::from([(
"custom".into(),
TargetDescriptor::default(),
)]))),
..Default::default()
}),
)
.await;

assert_eq!(
targets.map_err(|e| e.to_string()),
Ok(RequestResult::Target(TargetRequestOutput {
entry: PathBuf::default(),
targets: vec![Target {
dist_dir: package_dir().join("dist").join("custom"),
dist_entry: None,
env: Arc::new(Environment {
context: EnvironmentContext::Browser,
engines: Engines {
browsers: Some(EnginesBrowsers::default()),
..Engines::default()
},
is_library: false,
output_format: OutputFormat::Global,
should_optimize: true,
should_scope_hoist: false,
..Environment::default()
}),
name: String::from("custom"),
..Target::default()
}]
}))
);
}

#[tokio::test(flavor = "multi_thread")]
async fn returns_only_requested_custom_targets() {
let targets = targets_from_config(
Expand All @@ -1428,7 +1476,7 @@ mod tests {
),
None,
Some(AtlaspackOptions {
targets: Some(vec!["custom-two".into()]),
targets: Some(Targets::Filter(vec!["custom-two".into()])),
..Default::default()
}),
)
Expand Down
36 changes: 1 addition & 35 deletions crates/atlaspack/src/requests/target_request/package_json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ use std::fmt::Display;
use std::path::{Path, PathBuf};

use atlaspack_core::types::engines::Engines;
use atlaspack_core::types::EnvironmentContext;
use atlaspack_core::types::OutputFormat;
use atlaspack_core::types::TargetSourceMapOptions;
use atlaspack_resolver::IncludeNodeModules;
use atlaspack_core::types::TargetDescriptor;
use serde::Deserialize;
use serde::Deserializer;
use serde_json::Value;
Expand Down Expand Up @@ -35,23 +33,6 @@ pub enum BuiltInTargetDescriptor {
TargetDescriptor(TargetDescriptor),
}

#[derive(Debug, Clone, Default, Deserialize, PartialEq)]
#[serde(default, rename_all = "camelCase")]
pub struct TargetDescriptor {
pub context: Option<EnvironmentContext>,
pub dist_dir: Option<PathBuf>,
pub dist_entry: Option<PathBuf>,
pub engines: Option<Engines>,
pub include_node_modules: Option<IncludeNodeModules>,
pub is_library: Option<bool>,
pub optimize: Option<bool>,
pub output_format: Option<OutputFormat>,
pub public_url: Option<String>,
pub scope_hoist: Option<bool>,
pub source: Option<SourceField>,
pub source_map: Option<SourceMapField>,
}

#[derive(Debug, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ModuleFormat {
Expand Down Expand Up @@ -99,21 +80,6 @@ pub struct PackageJson {
pub fields: HashMap<String, serde_json::Value>,
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
pub enum SourceField {
#[allow(unused)]
Source(String),
#[allow(unused)]
Sources(Vec<String>),
}

#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(untagged)]
pub enum SourceMapField {
Bool(bool),
Options(TargetSourceMapOptions),
}

fn browser_field<'de, D>(deserializer: D) -> Result<Option<BrowserField>, D::Error>
where
D: Deserializer<'de>,
Expand Down
44 changes: 43 additions & 1 deletion crates/atlaspack_core/src/types/atlaspack_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use serde::Deserializer;
use serde::Serialize;

use super::engines::Engines;
use super::EnvironmentContext;
use super::IncludeNodeModules;
use super::OutputFormat;
use super::TargetSourceMapOptions;

/// The options passed into Atlaspack either through the CLI or the programmatic API
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
Expand Down Expand Up @@ -37,7 +40,46 @@ pub struct AtlaspackOptions {

pub threads: Option<usize>,

pub targets: Option<Vec<String>>,
pub targets: Option<Targets>,
}

#[derive(Clone, Debug, Hash, PartialEq, Deserialize, Serialize)]
#[serde(untagged)]
pub enum Targets {
Filter(Vec<String>),
CustomTarget(BTreeMap<String, TargetDescriptor>),
}

#[derive(Debug, Clone, Deserialize, Hash, PartialEq, Serialize)]
pub enum SourceField {
#[allow(unused)]
Source(String),
#[allow(unused)]
Sources(Vec<String>),
}

#[derive(Debug, Clone, Deserialize, Hash, PartialEq, Serialize)]
#[serde(untagged)]
pub enum SourceMapField {
Bool(bool),
Options(TargetSourceMapOptions),
}

#[derive(Debug, Clone, Default, Deserialize, Hash, PartialEq, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct TargetDescriptor {
pub context: Option<EnvironmentContext>,
pub dist_dir: Option<PathBuf>,
pub dist_entry: Option<PathBuf>,
pub engines: Option<Engines>,
pub include_node_modules: Option<IncludeNodeModules>,
pub is_library: Option<bool>,
pub optimize: Option<bool>,
pub output_format: Option<OutputFormat>,
pub public_url: Option<String>,
pub scope_hoist: Option<bool>,
pub source: Option<SourceField>,
pub source_map: Option<SourceMapField>,
}

#[derive(Clone, Debug, Default, Hash, PartialEq, Serialize)]
Expand Down
93 changes: 39 additions & 54 deletions packages/core/integration-tests/test/javascript.js
Original file line number Diff line number Diff line change
Expand Up @@ -1871,7 +1871,7 @@ describe('javascript', function () {
assert.equal(output(), true);
});

it.v2('should not touch process.browser for target node', async function () {
it('should not touch process.browser for target node', async function () {
let b = await bundle(
path.join(__dirname, '/integration/process/index.js'),
{
Expand All @@ -1889,26 +1889,23 @@ describe('javascript', function () {
assert.equal(output(), false);
});

it.v2(
'should not touch process.browser for target electron-main',
async function () {
let b = await bundle(
path.join(__dirname, '/integration/process/index.js'),
{
targets: {
main: {
context: 'electron-main',
distDir: path.join(__dirname, '/integration/process/dist.js'),
},
it('should not touch process.browser for target electron-main', async function () {
let b = await bundle(
path.join(__dirname, '/integration/process/index.js'),
{
targets: {
main: {
context: 'electron-main',
distDir: path.join(__dirname, '/integration/process/dist.js'),
},
},
);
},
);

let output = await run(b);
assert.ok(output.toString().indexOf('process.browser') !== -1);
assert.equal(output(), false);
},
);
let output = await run(b);
assert.ok(output.toString().indexOf('process.browser') !== -1);
assert.equal(output(), false);
});

it('should replace process.browser for target electron-renderer', async function () {
let b = await bundle(
Expand Down Expand Up @@ -2000,25 +1997,19 @@ describe('javascript', function () {
},
);

it.v2(
'should not exclude resolving specifiers that map to false in the browser field in node builds',
async () => {
let b = await bundle(
path.join(
__dirname,
'/integration/resolve-entries/pkg-ignore-browser/index.js',
),
{
targets: ['node'],
},
);
it('should not exclude resolving specifiers that map to false in the browser field in node builds', async () => {
let b = await bundle(
path.join(
__dirname,
'/integration/resolve-entries/pkg-ignore-browser/index.js',
),
{
targets: ['node'],
},
);

assert.equal(
await run(b),
'this should only exist in non-browser builds',
);
},
);
assert.equal(await run(b), 'this should only exist in non-browser builds');
});

it.skip('should not resolve the browser field for --target=node', async function () {
let b = await bundle(
Expand Down Expand Up @@ -3458,26 +3449,20 @@ describe('javascript', function () {
assert.deepEqual(res, {a: 4});
});

// Enable this for v3 once hmr options is supported in the js_transformer

it.v2(
'should not use arrow functions for reexport declarations unless supported',
async function () {
// TODO: Fails in v3 due to "ENOENT: no such file or directory" for the
let b = await bundle(
path.join(__dirname, 'integration/js-export-arrow-support/index.js'),
{
// Remove comments containing "=>"
defaultTargetOptions: {
shouldOptimize: true,
},
it('should not use arrow functions for reexport declarations unless supported', async function () {
let b = await bundle(
path.join(__dirname, 'integration/js-export-arrow-support/index.js'),
{
// Remove comments containing "=>"
defaultTargetOptions: {
shouldOptimize: true,
},
);
},
);

let content = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
assert(!content.includes('=>'));
},
);
let content = await outputFS.readFile(b.getBundles()[0].filePath, 'utf8');
assert(!content.includes('=>'));
});

it('should support classes that extend from another using default browsers', async () => {
await fsFixture(overlayFS, __dirname)`
Expand Down

0 comments on commit 45a90ae

Please sign in to comment.