@zenithbuild/bundler 1.3.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.
- package/CLAUDE.md +111 -0
- package/Cargo.lock +4244 -0
- package/Cargo.toml +65 -0
- package/README.md +135 -0
- package/build.rs +5 -0
- package/dev-server.js +117 -0
- package/index.js +18 -0
- package/package.json +14 -0
- package/src/bundler.rs +81 -0
- package/src/css.rs +266 -0
- package/src/html.rs +147 -0
- package/src/lib.rs +116 -0
- package/src/plugin.rs +332 -0
- package/src/store.rs +44 -0
- package/tests/fixtures/hello.zen +19 -0
- package/tests/integration.rs +53 -0
- package/tsconfig.json +29 -0
package/src/plugin.rs
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
//! ZenithPlugin - Rolldown Plugin for .zen file compilation
|
|
2
|
+
//!
|
|
3
|
+
//! Implements the Rolldown Plugin trait to:
|
|
4
|
+
//! 1. Intercept `.zen` file imports via `resolve_id`
|
|
5
|
+
//! 2. Compile `.zen` files via Zenith compiler in `load`
|
|
6
|
+
//! 3. Buffer CSS for later pruning/stitching
|
|
7
|
+
//! 4. Emit optimized CSS in `generate_bundle`
|
|
8
|
+
|
|
9
|
+
use std::sync::Arc;
|
|
10
|
+
|
|
11
|
+
use dashmap::DashMap;
|
|
12
|
+
use rolldown_plugin::{
|
|
13
|
+
Plugin, PluginContext, HookResolveIdArgs, HookResolveIdOutput,
|
|
14
|
+
HookLoadArgs, HookLoadOutput, HookGenerateBundleArgs, HookUsage,
|
|
15
|
+
HookTransformArgs, HookTransformReturn,
|
|
16
|
+
LoadPluginContext, TransformPluginContext,
|
|
17
|
+
};
|
|
18
|
+
use rolldown_common::{EmittedAsset, ResolvedExternal, OutputAsset, OutputChunk, Output, StrOrBytes};
|
|
19
|
+
|
|
20
|
+
use crate::css::CssBuffer;
|
|
21
|
+
use crate::store::AssetStore;
|
|
22
|
+
|
|
23
|
+
// Re-export ZenManifestExport from compiler-native as our canonical Manifest type
|
|
24
|
+
pub use compiler_native::{ZenManifestExport as ZenManifest, compile_zen_internal, CompileOptions, CompileResult};
|
|
25
|
+
|
|
26
|
+
/// The Zenith Plugin for Rolldown
|
|
27
|
+
#[derive(Debug)]
|
|
28
|
+
pub struct ZenithPlugin {
|
|
29
|
+
/// Buffer for CSS extracted from .zen files
|
|
30
|
+
css_buffer: Arc<CssBuffer>,
|
|
31
|
+
/// Collected CSS classes for pruning
|
|
32
|
+
used_classes: Arc<DashMap<String, ()>>,
|
|
33
|
+
/// Components directory path
|
|
34
|
+
components_dir: Option<String>,
|
|
35
|
+
/// User's entry point (e.g., "./src/main.zen")
|
|
36
|
+
entry_point: String,
|
|
37
|
+
|
|
38
|
+
/// In-memory asset store for Dev Server (optional)
|
|
39
|
+
store: Option<Arc<AssetStore>>,
|
|
40
|
+
|
|
41
|
+
/// Dev mode flag (enables HMR footer injection)
|
|
42
|
+
is_dev: bool,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
impl ZenithPlugin {
|
|
46
|
+
pub fn new(entry_point: impl Into<String>) -> Self {
|
|
47
|
+
Self {
|
|
48
|
+
css_buffer: Arc::new(CssBuffer::new()),
|
|
49
|
+
used_classes: Arc::new(DashMap::new()),
|
|
50
|
+
components_dir: None,
|
|
51
|
+
entry_point: entry_point.into(),
|
|
52
|
+
store: None,
|
|
53
|
+
is_dev: false,
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
pub fn with_store(mut self, store: Arc<AssetStore>) -> Self {
|
|
58
|
+
self.store = Some(store);
|
|
59
|
+
self
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
pub fn with_dev_mode(mut self, is_dev: bool) -> Self {
|
|
63
|
+
self.is_dev = is_dev;
|
|
64
|
+
self
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
pub fn with_components_dir(mut self, dir: impl Into<String>) -> Self {
|
|
68
|
+
self.components_dir = Some(dir.into());
|
|
69
|
+
self
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/// Get the collected CSS buffer for final emission
|
|
73
|
+
pub fn css_buffer(&self) -> Arc<CssBuffer> {
|
|
74
|
+
Arc::clone(&self.css_buffer)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/// Get all used CSS classes for pruning
|
|
78
|
+
pub fn used_classes(&self) -> Vec<String> {
|
|
79
|
+
self.used_classes.iter().map(|r| r.key().clone()).collect()
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
impl Plugin for ZenithPlugin {
|
|
84
|
+
fn name(&self) -> std::borrow::Cow<'static, str> {
|
|
85
|
+
std::borrow::Cow::Borrowed("zenith")
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
fn register_hook_usage(&self) -> HookUsage {
|
|
89
|
+
HookUsage::ResolveId | HookUsage::Load | HookUsage::GenerateBundle | HookUsage::Transform
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// Inject HMR footer if in dev mode
|
|
93
|
+
async fn transform(
|
|
94
|
+
&self,
|
|
95
|
+
_ctx: std::sync::Arc<TransformPluginContext>,
|
|
96
|
+
args: &HookTransformArgs<'_>,
|
|
97
|
+
) -> HookTransformReturn {
|
|
98
|
+
if !self.is_dev {
|
|
99
|
+
return Ok(None);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if args.id.ends_with(".zen") {
|
|
103
|
+
let mut code = args.code.to_string();
|
|
104
|
+
// Inject HMR Logic
|
|
105
|
+
let footer = format!(
|
|
106
|
+
r#"
|
|
107
|
+
if (import.meta.hot) {{
|
|
108
|
+
import.meta.hot.accept((newModule) => {{
|
|
109
|
+
// Surgical Re-Mount Logic
|
|
110
|
+
// Find anchors with data-z-id matching this file?
|
|
111
|
+
// For now, reload page if hydration fails?
|
|
112
|
+
// Or assume the component handles re-mount?
|
|
113
|
+
// newModule.default(target, props);
|
|
114
|
+
}});
|
|
115
|
+
}}
|
|
116
|
+
"#
|
|
117
|
+
);
|
|
118
|
+
code.push_str(&footer);
|
|
119
|
+
|
|
120
|
+
return Ok(Some(rolldown_plugin::HookTransformOutput {
|
|
121
|
+
code: Some(code),
|
|
122
|
+
..Default::default()
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
Ok(None)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// Intercept .zen file imports
|
|
129
|
+
async fn resolve_id(
|
|
130
|
+
&self,
|
|
131
|
+
_ctx: &PluginContext,
|
|
132
|
+
args: &HookResolveIdArgs<'_>,
|
|
133
|
+
) -> rolldown_plugin::HookResolveIdReturn {
|
|
134
|
+
let specifier = args.specifier;
|
|
135
|
+
|
|
136
|
+
// Handle .zen files
|
|
137
|
+
if specifier.ends_with(".zen") {
|
|
138
|
+
return Ok(Some(HookResolveIdOutput {
|
|
139
|
+
id: specifier.to_string().into(),
|
|
140
|
+
external: Some(ResolvedExternal::Bool(false)),
|
|
141
|
+
..Default::default()
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Handle virtual entry
|
|
146
|
+
if specifier == "virtual:zenith-entry" || specifier.starts_with("\0zenith:") {
|
|
147
|
+
return Ok(Some(HookResolveIdOutput {
|
|
148
|
+
id: specifier.to_string().into(),
|
|
149
|
+
external: Some(ResolvedExternal::Bool(false)),
|
|
150
|
+
..Default::default()
|
|
151
|
+
}));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
Ok(None)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/// Load and compile .zen files
|
|
158
|
+
async fn load(
|
|
159
|
+
&self,
|
|
160
|
+
_ctx: Arc<LoadPluginContext>,
|
|
161
|
+
args: &HookLoadArgs<'_>,
|
|
162
|
+
) -> rolldown_plugin::HookLoadReturn {
|
|
163
|
+
let id = &args.id;
|
|
164
|
+
|
|
165
|
+
// Handle virtual entry - this is the Hydration Controller
|
|
166
|
+
if &**id == "virtual:zenith-entry" {
|
|
167
|
+
return Ok(Some(HookLoadOutput {
|
|
168
|
+
code: self.generate_hydration_controller().into(),
|
|
169
|
+
..Default::default()
|
|
170
|
+
}));
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Handle .zen files
|
|
174
|
+
if id.ends_with(".zen") {
|
|
175
|
+
let source = match std::fs::read_to_string(&**id) {
|
|
176
|
+
Ok(s) => s,
|
|
177
|
+
Err(e) => {
|
|
178
|
+
return Err(anyhow::anyhow!("Failed to read .zen file: {}", e));
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Compile using internal Rust-to-Rust API (no JSON serialization)
|
|
183
|
+
let result = compile_zen_internal(&source, &**id, CompileOptions::default())
|
|
184
|
+
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
|
185
|
+
|
|
186
|
+
if result.has_errors {
|
|
187
|
+
return Err(anyhow::anyhow!("Compilation errors: {:?}", result.errors));
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Get manifest for capability info
|
|
191
|
+
let manifest = result.manifest.ok_or_else(|| anyhow::anyhow!("No manifest generated"))?;
|
|
192
|
+
|
|
193
|
+
// Buffer the CSS for later pruning/emission
|
|
194
|
+
if !manifest.styles.is_empty() {
|
|
195
|
+
self.css_buffer.insert(id.to_string(), manifest.styles.clone());
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Collect CSS classes for pruning
|
|
199
|
+
for class in &manifest.css_classes {
|
|
200
|
+
self.used_classes.insert(class.to_owned(), ());
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Generate the module code (script + expressions)
|
|
204
|
+
let js_code = self.generate_module_code(&manifest);
|
|
205
|
+
|
|
206
|
+
return Ok(Some(HookLoadOutput {
|
|
207
|
+
code: js_code.into(),
|
|
208
|
+
..Default::default()
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
Ok(None)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// Emit the final optimized CSS asset
|
|
216
|
+
async fn generate_bundle(
|
|
217
|
+
&self,
|
|
218
|
+
ctx: &PluginContext,
|
|
219
|
+
args: &mut HookGenerateBundleArgs<'_>,
|
|
220
|
+
) -> rolldown_plugin::HookNoopReturn {
|
|
221
|
+
// 1. Populate Store (if present)
|
|
222
|
+
if let Some(store) = &self.store {
|
|
223
|
+
for output in args.bundle.iter() {
|
|
224
|
+
match output {
|
|
225
|
+
Output::Asset(a) => {
|
|
226
|
+
// Attempt to extract source string
|
|
227
|
+
// rolldown_common::StrOrBytes (Assuming Str/Bytes variants)
|
|
228
|
+
let source = match &a.source {
|
|
229
|
+
StrOrBytes::Str(s) => s.to_string(),
|
|
230
|
+
StrOrBytes::Bytes(b) => String::from_utf8_lossy(b).to_string(),
|
|
231
|
+
};
|
|
232
|
+
store.update(a.filename.to_string(), source);
|
|
233
|
+
}
|
|
234
|
+
Output::Chunk(c) => {
|
|
235
|
+
store.update(c.filename.to_string(), c.code.clone());
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
let used_classes = self.used_classes();
|
|
242
|
+
let css_content = self.css_buffer.stitch_and_prune(&used_classes)
|
|
243
|
+
.map_err(|e| anyhow::anyhow!("{}", e))?;
|
|
244
|
+
|
|
245
|
+
if !css_content.is_empty() {
|
|
246
|
+
// Emit the CSS asset
|
|
247
|
+
let asset = EmittedAsset {
|
|
248
|
+
name: Some("zenith.css".into()),
|
|
249
|
+
file_name: None,
|
|
250
|
+
original_file_name: None,
|
|
251
|
+
source: css_content.into_bytes().into(),
|
|
252
|
+
};
|
|
253
|
+
ctx.emit_file(asset, None, None)?;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Ok(())
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
impl ZenithPlugin {
|
|
261
|
+
/// Generate the Hydration Controller (Bootstrap Loader)
|
|
262
|
+
///
|
|
263
|
+
/// This is the entry point that:
|
|
264
|
+
/// 1. Immediately: Sets up event delegation (zero-cost, <2KB)
|
|
265
|
+
/// 2. Deferred: Imports the actual app logic via dynamic import
|
|
266
|
+
/// 3. Trigger: Idle callback or timeout
|
|
267
|
+
fn generate_hydration_controller(&self) -> String {
|
|
268
|
+
let entry = &self.entry_point;
|
|
269
|
+
format!(r#"
|
|
270
|
+
// === ZENITH HYDRATION CONTROLLER ===
|
|
271
|
+
// Generated by ZenithPlugin
|
|
272
|
+
|
|
273
|
+
import {{ delegateEvents }} from 'zenith/runtime/core';
|
|
274
|
+
|
|
275
|
+
// 1. Immediate: Global listeners (The "Zero-Cost" part)
|
|
276
|
+
delegateEvents();
|
|
277
|
+
|
|
278
|
+
// 2. Deferred: The actual App Logic (The "Heavy" part)
|
|
279
|
+
// We wrap the user's entry in a dynamic import to keep it off the main thread
|
|
280
|
+
const hydrate = () => import('{entry}');
|
|
281
|
+
|
|
282
|
+
// 3. Trigger: Interaction or Idle
|
|
283
|
+
if ('requestIdleCallback' in window) {{
|
|
284
|
+
requestIdleCallback(hydrate, {{ timeout: 2000 }});
|
|
285
|
+
}} else {{
|
|
286
|
+
// Fallback for Safari/older browsers
|
|
287
|
+
setTimeout(hydrate, 200);
|
|
288
|
+
}}
|
|
289
|
+
"#)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/// Generate the module code for a compiled .zen file
|
|
293
|
+
fn generate_module_code(&self, manifest: &ZenManifest) -> String {
|
|
294
|
+
let mut code = String::new();
|
|
295
|
+
|
|
296
|
+
// NPM imports first
|
|
297
|
+
if !manifest.npm_imports.is_empty() {
|
|
298
|
+
code.push_str(&manifest.npm_imports);
|
|
299
|
+
code.push('\n');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Author script (component logic)
|
|
303
|
+
if !manifest.script.is_empty() {
|
|
304
|
+
code.push_str("\n// --- COMPONENT SCRIPT ---\n");
|
|
305
|
+
code.push_str(&manifest.script);
|
|
306
|
+
code.push('\n');
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Expressions (reactive bindings)
|
|
310
|
+
if !manifest.expressions.is_empty() {
|
|
311
|
+
code.push_str("\n// --- EXPRESSIONS ---\n");
|
|
312
|
+
code.push_str(&manifest.expressions);
|
|
313
|
+
code.push('\n');
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Template (for hydration)
|
|
317
|
+
if !manifest.template.is_empty() {
|
|
318
|
+
code.push_str("\n// --- TEMPLATE (for hydration) ---\n");
|
|
319
|
+
code.push_str(&format!("export const __ZENITH_TEMPLATE__ = `{}`;\n",
|
|
320
|
+
manifest.template.replace("`", "\\`").replace("${", "\\${")));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// Export capabilities for code splitting
|
|
324
|
+
code.push_str("\n// --- CAPABILITIES ---\n");
|
|
325
|
+
code.push_str(&format!("export const __ZENITH_CAPABILITIES__ = {:?};\n", manifest.required_capabilities));
|
|
326
|
+
code.push_str(&format!("export const __ZENITH_USES_STATE__ = {};\n", manifest.uses_state));
|
|
327
|
+
code.push_str(&format!("export const __ZENITH_HAS_EVENTS__ = {};\n", manifest.has_events));
|
|
328
|
+
code.push_str(&format!("export const __ZENITH_IS_STATIC__ = {};\n", manifest.is_static));
|
|
329
|
+
|
|
330
|
+
code
|
|
331
|
+
}
|
|
332
|
+
}
|
package/src/store.rs
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//! In-memory Asset Store for Dev Server
|
|
2
|
+
//!
|
|
3
|
+
//! Provides a thread-safe DashMap to store compiled assets (JS/CSS)
|
|
4
|
+
//! for memory-only serving in dev mode.
|
|
5
|
+
|
|
6
|
+
use dashmap::DashMap;
|
|
7
|
+
use std::sync::Arc;
|
|
8
|
+
|
|
9
|
+
/// Thread-safe in-memory asset store
|
|
10
|
+
#[derive(Debug, Clone)]
|
|
11
|
+
pub struct AssetStore {
|
|
12
|
+
/// Map of normalized file path (starts with /) to content
|
|
13
|
+
assets: Arc<DashMap<String, String>>,
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
impl AssetStore {
|
|
17
|
+
pub fn new() -> Self {
|
|
18
|
+
Self {
|
|
19
|
+
assets: Arc::new(DashMap::new()),
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/// Update asset content
|
|
24
|
+
/// Automatically ensures path starts with /
|
|
25
|
+
pub fn update(&self, path: String, content: String) {
|
|
26
|
+
let normalized = if path.starts_with('/') {
|
|
27
|
+
path
|
|
28
|
+
} else {
|
|
29
|
+
format!("/{}", path)
|
|
30
|
+
};
|
|
31
|
+
self.assets.insert(normalized, content);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/// Retrieve asset content
|
|
35
|
+
pub fn get(&self, path: &str) -> Option<String> {
|
|
36
|
+
self.assets.get(path).map(|r| r.value().clone())
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
impl Default for AssetStore {
|
|
41
|
+
fn default() -> Self {
|
|
42
|
+
Self::new()
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="hello">
|
|
3
|
+
<h1>Hello {{ name }}</h1>
|
|
4
|
+
<p class="description">Welcome to Zenith</p>
|
|
5
|
+
</div>
|
|
6
|
+
</template>
|
|
7
|
+
|
|
8
|
+
<script>
|
|
9
|
+
prop name: string;
|
|
10
|
+
|
|
11
|
+
const greeting = "Hello";
|
|
12
|
+
console.log(greeting, name);
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<style>
|
|
16
|
+
.hello { color: red; }
|
|
17
|
+
.description { font-size: 1.2rem; }
|
|
18
|
+
.unused { color: blue; }
|
|
19
|
+
</style>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//! Integration Tests for Zenith Bundler
|
|
2
|
+
//!
|
|
3
|
+
//! Verifies the full compilation pipeline using the Rolldown integration.
|
|
4
|
+
|
|
5
|
+
use std::path::PathBuf;
|
|
6
|
+
use zenith_bundler::bundler::create_zenith_bundler;
|
|
7
|
+
|
|
8
|
+
#[tokio::test]
|
|
9
|
+
async fn test_compile_hello_zen() {
|
|
10
|
+
let fixture_path = PathBuf::from("tests/fixtures/hello.zen");
|
|
11
|
+
let cwd = std::env::current_dir().unwrap();
|
|
12
|
+
let absolute_path = cwd.join(fixture_path);
|
|
13
|
+
let entry_str = absolute_path.to_str().unwrap();
|
|
14
|
+
|
|
15
|
+
// 1. Create the Bundler
|
|
16
|
+
let mut bundler = create_zenith_bundler(entry_str, None);
|
|
17
|
+
|
|
18
|
+
// 2. Generate the bundle (in-memory)
|
|
19
|
+
// bundler.generate() takes no arguments in the current version
|
|
20
|
+
let result = bundler.generate().await;
|
|
21
|
+
|
|
22
|
+
match result {
|
|
23
|
+
Ok(outputs) => {
|
|
24
|
+
println!("Bundle generation success!");
|
|
25
|
+
|
|
26
|
+
// 3. Verify Assets
|
|
27
|
+
for item in outputs.assets {
|
|
28
|
+
// Rolldown output is an enum (Asset or Chunk)
|
|
29
|
+
match item {
|
|
30
|
+
rolldown_common::Output::Asset(asset) => {
|
|
31
|
+
println!("Asset: {}", asset.filename);
|
|
32
|
+
if asset.filename.ends_with(".css") {
|
|
33
|
+
let content = match &asset.source {
|
|
34
|
+
rolldown_common::StrOrBytes::Str(s) => s.to_string(),
|
|
35
|
+
rolldown_common::StrOrBytes::Bytes(b) => String::from_utf8_lossy(b).to_string(),
|
|
36
|
+
};
|
|
37
|
+
assert!(content.contains(".hello"), "CSS should contain used classes");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
rolldown_common::Output::Chunk(chunk) => {
|
|
41
|
+
println!("Chunk: {}", chunk.filename);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
Err(e) => {
|
|
47
|
+
// It's possible that without proper semantic analysis setup (OXC stuff)
|
|
48
|
+
// or node modules resolution, this might fail.
|
|
49
|
+
// But for a simple .zen file with no imports, it should work.
|
|
50
|
+
panic!("Bundler failed: {:?}", e);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// Environment setup & latest features
|
|
4
|
+
"lib": ["ESNext"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"module": "Preserve",
|
|
7
|
+
"moduleDetection": "force",
|
|
8
|
+
"jsx": "react-jsx",
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
|
|
11
|
+
// Bundler mode
|
|
12
|
+
"moduleResolution": "bundler",
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"verbatimModuleSyntax": true,
|
|
15
|
+
"noEmit": true,
|
|
16
|
+
|
|
17
|
+
// Best practices
|
|
18
|
+
"strict": true,
|
|
19
|
+
"skipLibCheck": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"noUncheckedIndexedAccess": true,
|
|
22
|
+
"noImplicitOverride": true,
|
|
23
|
+
|
|
24
|
+
// Some stricter flags (disabled by default)
|
|
25
|
+
"noUnusedLocals": false,
|
|
26
|
+
"noUnusedParameters": false,
|
|
27
|
+
"noPropertyAccessFromIndexSignature": false
|
|
28
|
+
}
|
|
29
|
+
}
|