[{"data":1,"prerenderedAt":3040},["ShallowReactive",2],{"page-\u002Fdart\u002F15-dart-for-the-web":3},{"id":4,"title":5,"body":6,"description":3033,"extension":3034,"meta":3035,"navigation":77,"path":3036,"seo":3037,"stem":3038,"__hash__":3039},"content\u002Fdart\u002F15-dart-for-the-web.md","Dart — Web Compilation, JS Interop & Cross-Platform Patterns",{"type":7,"value":8,"toc":3017},"minimark",[9,13,18,208,216,797,802,1180,1184,1494,1498,1711,1715,1894,1901,2341,2345,2448,2452,2595,2599,2606,2716,2719,3013],[10,11,5],"h1",{"id":12},"dart-web-compilation-js-interop-cross-platform-patterns",[14,15,17],"h2",{"id":16},"compilation-targets-dart2js-ddc-wasm","Compilation Targets — dart2js, DDC, Wasm",[19,20,22],"code-wrapper",{"language":21},"bash",[23,24,28],"pre",{"className":25,"code":26,"language":21,"meta":27,"style":27},"language-bash shiki shiki-themes github-light github-dark","# ── DDC (Dart Development Compiler) — dev mode ──\n# Fast compilation, readable JS, hot reload. Used by `webdev serve`.\n# Produces per-library modules (good for debugging).\ndart run build_runner serve web:8080\n\n# ── dart2js — production ──\n# AOT-like, slow compilation, minified + optimized JS. Fast runtime.\n# Tree-shaken, dead-code-eliminated. Single JS file + source map.\ndart compile js -O2 -o build\u002Fweb\u002Fmain.js lib\u002Fmain.dart\n# -O0: no optimization (debugging)\n# -O2: recommended for production (small, fast)\n# -O4: aggressive (may break some patterns — test thoroughly)\n\n# ── Wasm (experimental) ──\n# Compiles to WebAssembly. Better type fidelity (Dart types → Wasm types),\n# potentially faster execution. Still maturing.\ndart compile wasm -o build\u002Fweb\u002Fmain.wasm lib\u002Fmain.dart\n\n# ── Verify behavior differs between DDC and dart2js ──\n# DDC: readable JS, runtime type checks, asserts enabled.\n# dart2js: minified, asserts stripped, aggressive optimizations.\n# Test production with dart2js, not just DDC in dev.\n","",[29,30,31,40,46,52,72,79,85,91,97,121,127,133,139,144,150,156,162,179,184,190,196,202],"code",{"__ignoreMap":27},[32,33,36],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"sdCPZ","# ── DDC (Dart Development Compiler) — dev mode ──\n",[32,41,43],{"class":34,"line":42},2,[32,44,45],{"class":38},"# Fast compilation, readable JS, hot reload. Used by `webdev serve`.\n",[32,47,49],{"class":34,"line":48},3,[32,50,51],{"class":38},"# Produces per-library modules (good for debugging).\n",[32,53,55,59,63,66,69],{"class":34,"line":54},4,[32,56,58],{"class":57},"sIsaT","dart",[32,60,62],{"class":61},"sJ6F3"," run",[32,64,65],{"class":61}," build_runner",[32,67,68],{"class":61}," serve",[32,70,71],{"class":61}," web:8080\n",[32,73,75],{"class":34,"line":74},5,[32,76,78],{"emptyLinePlaceholder":77},true,"\n",[32,80,82],{"class":34,"line":81},6,[32,83,84],{"class":38},"# ── dart2js — production ──\n",[32,86,88],{"class":34,"line":87},7,[32,89,90],{"class":38},"# AOT-like, slow compilation, minified + optimized JS. Fast runtime.\n",[32,92,94],{"class":34,"line":93},8,[32,95,96],{"class":38},"# Tree-shaken, dead-code-eliminated. Single JS file + source map.\n",[32,98,100,102,105,108,112,115,118],{"class":34,"line":99},9,[32,101,58],{"class":57},[32,103,104],{"class":61}," compile",[32,106,107],{"class":61}," js",[32,109,111],{"class":110},"snvgF"," -O2",[32,113,114],{"class":110}," -o",[32,116,117],{"class":61}," build\u002Fweb\u002Fmain.js",[32,119,120],{"class":61}," lib\u002Fmain.dart\n",[32,122,124],{"class":34,"line":123},10,[32,125,126],{"class":38},"# -O0: no optimization (debugging)\n",[32,128,130],{"class":34,"line":129},11,[32,131,132],{"class":38},"# -O2: recommended for production (small, fast)\n",[32,134,136],{"class":34,"line":135},12,[32,137,138],{"class":38},"# -O4: aggressive (may break some patterns — test thoroughly)\n",[32,140,142],{"class":34,"line":141},13,[32,143,78],{"emptyLinePlaceholder":77},[32,145,147],{"class":34,"line":146},14,[32,148,149],{"class":38},"# ── Wasm (experimental) ──\n",[32,151,153],{"class":34,"line":152},15,[32,154,155],{"class":38},"# Compiles to WebAssembly. Better type fidelity (Dart types → Wasm types),\n",[32,157,159],{"class":34,"line":158},16,[32,160,161],{"class":38},"# potentially faster execution. Still maturing.\n",[32,163,165,167,169,172,174,177],{"class":34,"line":164},17,[32,166,58],{"class":57},[32,168,104],{"class":61},[32,170,171],{"class":61}," wasm",[32,173,114],{"class":110},[32,175,176],{"class":61}," build\u002Fweb\u002Fmain.wasm",[32,178,120],{"class":61},[32,180,182],{"class":34,"line":181},18,[32,183,78],{"emptyLinePlaceholder":77},[32,185,187],{"class":34,"line":186},19,[32,188,189],{"class":38},"# ── Verify behavior differs between DDC and dart2js ──\n",[32,191,193],{"class":34,"line":192},20,[32,194,195],{"class":38},"# DDC: readable JS, runtime type checks, asserts enabled.\n",[32,197,199],{"class":34,"line":198},21,[32,200,201],{"class":38},"# dart2js: minified, asserts stripped, aggressive optimizations.\n",[32,203,205],{"class":34,"line":204},22,[32,206,207],{"class":38},"# Test production with dart2js, not just DDC in dev.\n",[14,209,211,212,215],{"id":210},"js-interop-dartjs_interop-extension-types-dart-33","JS Interop — ",[29,213,214],{},"dart:js_interop"," & Extension Types (Dart 3.3+)",[19,217,218],{"language":58},[23,219,222],{"className":220,"code":221,"language":58,"meta":27,"style":27},"language-dart shiki shiki-themes github-light github-dark","import 'dart:js_interop';\n\n\u002F\u002F ── Declaring JS functions with @JS() ──\n@JS('Math.random')\nexternal double random();\n\n@JS('console.log')\nexternal void log(String message);\n\nvoid main() {\n  log('Hello from Dart');  \u002F\u002F calls JS console.log\n  print(random());  \u002F\u002F calls JS Math.random()\n}\n\n\u002F\u002F ── Wrapping JS objects with extension types (Dart 3.3+) ──\n\u002F\u002F Extension types provide a typed Dart interface over a JS object.\n\u002F\u002F Zero runtime overhead — the type is erased, the JS object is used directly.\n\nextension type JSPromise\u003CT>._(JSObject _) implements JSObject {\n  external static JSPromise\u003CT> resolve(T value);\n  external JSPromise\u003CT> then(JSFunction onFulfilled);\n  external JSPromise\u003CT> catch_(JSFunction onRejected);\n}\n\nextension type JSArray\u003CT>._(JSObject _) implements JSObject {\n  external T operator [](int index);\n  external int get length;\n  external void push(T value);\n}\n\n\u002F\u002F ── Calling a JS library (e.g., a charting library) ──\n@JS('Chart')\nextension type JSChart._(JSObject _) implements JSObject {\n  external factory JSChart(String selector, JSChartConfig config);\n  external void draw();\n}\n\nextension type JSChartConfig._(JSObject _) implements JSObject {\n  external factory JSChartConfig({\n    String type,\n    JSArray\u003CJSChartDataset> datasets,\n  });\n}\n\nextension type JSChartDataset._(JSObject _) implements JSObject {\n  external factory JSChartDataset({\n    String label,\n    JSArray\u003Cdouble> data,\n  });\n}\n",[29,223,224,237,241,246,260,274,278,289,307,311,322,338,354,359,363,368,373,378,382,414,441,464,486,491,496,520,540,554,570,575,580,586,598,619,642,654,659,664,684,696,705,719,725,730,735,755,766,774,787,792],{"__ignoreMap":27},[32,225,226,230,233],{"class":34,"line":35},[32,227,229],{"class":228},"svdQ7","import",[32,231,232],{"class":61}," 'dart:js_interop'",[32,234,236],{"class":235},"ssxIu",";\n",[32,238,239],{"class":34,"line":42},[32,240,78],{"emptyLinePlaceholder":77},[32,242,243],{"class":34,"line":48},[32,244,245],{"class":38},"\u002F\u002F ── Declaring JS functions with @JS() ──\n",[32,247,248,251,254,257],{"class":34,"line":54},[32,249,250],{"class":228},"@JS",[32,252,253],{"class":235},"(",[32,255,256],{"class":61},"'Math.random'",[32,258,259],{"class":235},")\n",[32,261,262,265,268,271],{"class":34,"line":74},[32,263,264],{"class":228},"external",[32,266,267],{"class":110}," double",[32,269,270],{"class":57}," random",[32,272,273],{"class":235},"();\n",[32,275,276],{"class":34,"line":81},[32,277,78],{"emptyLinePlaceholder":77},[32,279,280,282,284,287],{"class":34,"line":87},[32,281,250],{"class":228},[32,283,253],{"class":235},[32,285,286],{"class":61},"'console.log'",[32,288,259],{"class":235},[32,290,291,293,296,299,301,304],{"class":34,"line":93},[32,292,264],{"class":228},[32,294,295],{"class":228}," void",[32,297,298],{"class":57}," log",[32,300,253],{"class":235},[32,302,303],{"class":110},"String",[32,305,306],{"class":235}," message);\n",[32,308,309],{"class":34,"line":99},[32,310,78],{"emptyLinePlaceholder":77},[32,312,313,316,319],{"class":34,"line":123},[32,314,315],{"class":228},"void",[32,317,318],{"class":57}," main",[32,320,321],{"class":235},"() {\n",[32,323,324,327,329,332,335],{"class":34,"line":129},[32,325,326],{"class":57},"  log",[32,328,253],{"class":235},[32,330,331],{"class":61},"'Hello from Dart'",[32,333,334],{"class":235},");  ",[32,336,337],{"class":38},"\u002F\u002F calls JS console.log\n",[32,339,340,343,345,348,351],{"class":34,"line":135},[32,341,342],{"class":57},"  print",[32,344,253],{"class":235},[32,346,347],{"class":57},"random",[32,349,350],{"class":235},"());  ",[32,352,353],{"class":38},"\u002F\u002F calls JS Math.random()\n",[32,355,356],{"class":34,"line":141},[32,357,358],{"class":235},"}\n",[32,360,361],{"class":34,"line":146},[32,362,78],{"emptyLinePlaceholder":77},[32,364,365],{"class":34,"line":152},[32,366,367],{"class":38},"\u002F\u002F ── Wrapping JS objects with extension types (Dart 3.3+) ──\n",[32,369,370],{"class":34,"line":158},[32,371,372],{"class":38},"\u002F\u002F Extension types provide a typed Dart interface over a JS object.\n",[32,374,375],{"class":34,"line":164},[32,376,377],{"class":38},"\u002F\u002F Zero runtime overhead — the type is erased, the JS object is used directly.\n",[32,379,380],{"class":34,"line":181},[32,381,78],{"emptyLinePlaceholder":77},[32,383,384,387,390,393,396,399,402,405,408,411],{"class":34,"line":186},[32,385,386],{"class":228},"extension type",[32,388,389],{"class":110}," JSPromise",[32,391,392],{"class":235},"\u003C",[32,394,395],{"class":110},"T",[32,397,398],{"class":235},">._(",[32,400,401],{"class":110},"JSObject",[32,403,404],{"class":235}," _) ",[32,406,407],{"class":228},"implements",[32,409,410],{"class":110}," JSObject",[32,412,413],{"class":235}," {\n",[32,415,416,419,422,424,426,428,431,434,436,438],{"class":34,"line":192},[32,417,418],{"class":228},"  external",[32,420,421],{"class":228}," static",[32,423,389],{"class":110},[32,425,392],{"class":235},[32,427,395],{"class":110},[32,429,430],{"class":235},"> ",[32,432,433],{"class":57},"resolve",[32,435,253],{"class":235},[32,437,395],{"class":110},[32,439,440],{"class":235}," value);\n",[32,442,443,445,447,449,451,453,456,458,461],{"class":34,"line":198},[32,444,418],{"class":228},[32,446,389],{"class":110},[32,448,392],{"class":235},[32,450,395],{"class":110},[32,452,430],{"class":235},[32,454,455],{"class":57},"then",[32,457,253],{"class":235},[32,459,460],{"class":110},"JSFunction",[32,462,463],{"class":235}," onFulfilled);\n",[32,465,466,468,470,472,474,476,479,481,483],{"class":34,"line":204},[32,467,418],{"class":228},[32,469,389],{"class":110},[32,471,392],{"class":235},[32,473,395],{"class":110},[32,475,430],{"class":235},[32,477,478],{"class":57},"catch_",[32,480,253],{"class":235},[32,482,460],{"class":110},[32,484,485],{"class":235}," onRejected);\n",[32,487,489],{"class":34,"line":488},23,[32,490,358],{"class":235},[32,492,494],{"class":34,"line":493},24,[32,495,78],{"emptyLinePlaceholder":77},[32,497,499,501,504,506,508,510,512,514,516,518],{"class":34,"line":498},25,[32,500,386],{"class":228},[32,502,503],{"class":110}," JSArray",[32,505,392],{"class":235},[32,507,395],{"class":110},[32,509,398],{"class":235},[32,511,401],{"class":110},[32,513,404],{"class":235},[32,515,407],{"class":228},[32,517,410],{"class":110},[32,519,413],{"class":235},[32,521,523,525,528,531,534,537],{"class":34,"line":522},26,[32,524,418],{"class":228},[32,526,527],{"class":110}," T",[32,529,530],{"class":228}," operator",[32,532,533],{"class":235}," [](",[32,535,536],{"class":110},"int",[32,538,539],{"class":235}," index);\n",[32,541,543,545,548,551],{"class":34,"line":542},27,[32,544,418],{"class":228},[32,546,547],{"class":110}," int",[32,549,550],{"class":228}," get",[32,552,553],{"class":235}," length;\n",[32,555,557,559,561,564,566,568],{"class":34,"line":556},28,[32,558,418],{"class":228},[32,560,295],{"class":228},[32,562,563],{"class":57}," push",[32,565,253],{"class":235},[32,567,395],{"class":110},[32,569,440],{"class":235},[32,571,573],{"class":34,"line":572},29,[32,574,358],{"class":235},[32,576,578],{"class":34,"line":577},30,[32,579,78],{"emptyLinePlaceholder":77},[32,581,583],{"class":34,"line":582},31,[32,584,585],{"class":38},"\u002F\u002F ── Calling a JS library (e.g., a charting library) ──\n",[32,587,589,591,593,596],{"class":34,"line":588},32,[32,590,250],{"class":228},[32,592,253],{"class":235},[32,594,595],{"class":61},"'Chart'",[32,597,259],{"class":235},[32,599,601,603,606,609,611,613,615,617],{"class":34,"line":600},33,[32,602,386],{"class":228},[32,604,605],{"class":110}," JSChart",[32,607,608],{"class":235},"._(",[32,610,401],{"class":110},[32,612,404],{"class":235},[32,614,407],{"class":228},[32,616,410],{"class":110},[32,618,413],{"class":235},[32,620,622,624,627,629,631,633,636,639],{"class":34,"line":621},34,[32,623,418],{"class":228},[32,625,626],{"class":228}," factory",[32,628,605],{"class":110},[32,630,253],{"class":235},[32,632,303],{"class":110},[32,634,635],{"class":235}," selector, ",[32,637,638],{"class":110},"JSChartConfig",[32,640,641],{"class":235}," config);\n",[32,643,645,647,649,652],{"class":34,"line":644},35,[32,646,418],{"class":228},[32,648,295],{"class":228},[32,650,651],{"class":57}," draw",[32,653,273],{"class":235},[32,655,657],{"class":34,"line":656},36,[32,658,358],{"class":235},[32,660,662],{"class":34,"line":661},37,[32,663,78],{"emptyLinePlaceholder":77},[32,665,667,669,672,674,676,678,680,682],{"class":34,"line":666},38,[32,668,386],{"class":228},[32,670,671],{"class":110}," JSChartConfig",[32,673,608],{"class":235},[32,675,401],{"class":110},[32,677,404],{"class":235},[32,679,407],{"class":228},[32,681,410],{"class":110},[32,683,413],{"class":235},[32,685,687,689,691,693],{"class":34,"line":686},39,[32,688,418],{"class":228},[32,690,626],{"class":228},[32,692,671],{"class":110},[32,694,695],{"class":235},"({\n",[32,697,699,702],{"class":34,"line":698},40,[32,700,701],{"class":110},"    String",[32,703,704],{"class":235}," type,\n",[32,706,708,711,713,716],{"class":34,"line":707},41,[32,709,710],{"class":110},"    JSArray",[32,712,392],{"class":235},[32,714,715],{"class":110},"JSChartDataset",[32,717,718],{"class":235},"> datasets,\n",[32,720,722],{"class":34,"line":721},42,[32,723,724],{"class":235},"  });\n",[32,726,728],{"class":34,"line":727},43,[32,729,358],{"class":235},[32,731,733],{"class":34,"line":732},44,[32,734,78],{"emptyLinePlaceholder":77},[32,736,738,740,743,745,747,749,751,753],{"class":34,"line":737},45,[32,739,386],{"class":228},[32,741,742],{"class":110}," JSChartDataset",[32,744,608],{"class":235},[32,746,401],{"class":110},[32,748,404],{"class":235},[32,750,407],{"class":228},[32,752,410],{"class":110},[32,754,413],{"class":235},[32,756,758,760,762,764],{"class":34,"line":757},46,[32,759,418],{"class":228},[32,761,626],{"class":228},[32,763,742],{"class":110},[32,765,695],{"class":235},[32,767,769,771],{"class":34,"line":768},47,[32,770,701],{"class":110},[32,772,773],{"class":235}," label,\n",[32,775,777,779,781,784],{"class":34,"line":776},48,[32,778,710],{"class":110},[32,780,392],{"class":235},[32,782,783],{"class":110},"double",[32,785,786],{"class":235},"> data,\n",[32,788,790],{"class":34,"line":789},49,[32,791,724],{"class":235},[32,793,795],{"class":34,"line":794},50,[32,796,358],{"class":235},[798,799,801],"h3",{"id":800},"js-interop-conversion-between-dart-and-js","JS Interop — Conversion Between Dart and JS",[19,803,804],{"language":58},[23,805,807],{"className":220,"code":806,"language":58,"meta":27,"style":27},"import 'dart:js_interop';\n\n\u002F\u002F Dart ↔ JS type conversions (extension types handle the bridging):\n\nvoid main() {\n  \u002F\u002F String → JSString and back\n  JSString jsStr = 'hello'.toJS;\n  String dartStr = jsStr.toDart;\n\n  \u002F\u002F List → JSArray and back\n  JSArray\u003CJSNumber> jsArr = [1, 2, 3].map((n) => n.toJS).toList().toJS;\n  List\u003Cint> dartList = jsArr.toDart.map((js) => js.toDartInt).toList();\n\n  \u002F\u002F Map → JSObject and back\n  final jsObj = {'name': 'Alice', 'age': 30}.jsify() as JSObject;\n  final dartMap = jsObj.dartify() as Map\u003CString, dynamic>;\n\n  \u002F\u002F Number → JSNumber and back\n  JSNumber jsNum = 42.toJS;\n  int dartInt = jsNum.toDartInt;\n  double dartDouble = jsNum.toDartDouble;\n\n  \u002F\u002F bool → JSBoolean and back\n  JSBoolean jsBool = true.toJS;\n  bool dartBool = jsBool.toDart;\n}\n\n\u002F\u002F ❌ Anti-pattern: using `dynamic` for JS interop (no type safety).\n\u002F\u002F dynamic x = someJsObject;\n\u002F\u002F x.anything();  \u002F\u002F compiles, throws at runtime if method doesn't exist\n\n\u002F\u002F ✓ Correct: use extension types for typed JS interop.\n",[29,808,809,817,821,826,830,838,843,860,873,877,882,935,966,970,975,1023,1057,1061,1066,1082,1095,1108,1112,1117,1132,1145,1149,1153,1158,1163,1171,1175],{"__ignoreMap":27},[32,810,811,813,815],{"class":34,"line":35},[32,812,229],{"class":228},[32,814,232],{"class":61},[32,816,236],{"class":235},[32,818,819],{"class":34,"line":42},[32,820,78],{"emptyLinePlaceholder":77},[32,822,823],{"class":34,"line":48},[32,824,825],{"class":38},"\u002F\u002F Dart ↔ JS type conversions (extension types handle the bridging):\n",[32,827,828],{"class":34,"line":54},[32,829,78],{"emptyLinePlaceholder":77},[32,831,832,834,836],{"class":34,"line":74},[32,833,315],{"class":228},[32,835,318],{"class":57},[32,837,321],{"class":235},[32,839,840],{"class":34,"line":81},[32,841,842],{"class":38},"  \u002F\u002F String → JSString and back\n",[32,844,845,848,851,854,857],{"class":34,"line":87},[32,846,847],{"class":110},"  JSString",[32,849,850],{"class":235}," jsStr ",[32,852,853],{"class":228},"=",[32,855,856],{"class":61}," 'hello'",[32,858,859],{"class":235},".toJS;\n",[32,861,862,865,868,870],{"class":34,"line":93},[32,863,864],{"class":110},"  String",[32,866,867],{"class":235}," dartStr ",[32,869,853],{"class":228},[32,871,872],{"class":235}," jsStr.toDart;\n",[32,874,875],{"class":34,"line":99},[32,876,78],{"emptyLinePlaceholder":77},[32,878,879],{"class":34,"line":123},[32,880,881],{"class":38},"  \u002F\u002F List → JSArray and back\n",[32,883,884,887,889,892,895,897,900,903,906,909,911,914,917,920,923,926,929,932],{"class":34,"line":129},[32,885,886],{"class":110},"  JSArray",[32,888,392],{"class":235},[32,890,891],{"class":110},"JSNumber",[32,893,894],{"class":235},"> jsArr ",[32,896,853],{"class":228},[32,898,899],{"class":235}," [",[32,901,902],{"class":110},"1",[32,904,905],{"class":235},", ",[32,907,908],{"class":110},"2",[32,910,905],{"class":235},[32,912,913],{"class":110},"3",[32,915,916],{"class":235},"].",[32,918,919],{"class":57},"map",[32,921,922],{"class":235},"((n) ",[32,924,925],{"class":228},"=>",[32,927,928],{"class":235}," n.toJS).",[32,930,931],{"class":57},"toList",[32,933,934],{"class":235},"().toJS;\n",[32,936,937,940,942,944,947,949,952,954,957,959,962,964],{"class":34,"line":135},[32,938,939],{"class":110},"  List",[32,941,392],{"class":235},[32,943,536],{"class":110},[32,945,946],{"class":235},"> dartList ",[32,948,853],{"class":228},[32,950,951],{"class":235}," jsArr.toDart.",[32,953,919],{"class":57},[32,955,956],{"class":235},"((js) ",[32,958,925],{"class":228},[32,960,961],{"class":235}," js.toDartInt).",[32,963,931],{"class":57},[32,965,273],{"class":235},[32,967,968],{"class":34,"line":141},[32,969,78],{"emptyLinePlaceholder":77},[32,971,972],{"class":34,"line":146},[32,973,974],{"class":38},"  \u002F\u002F Map → JSObject and back\n",[32,976,977,980,983,985,988,991,994,997,999,1002,1004,1007,1010,1013,1016,1019,1021],{"class":34,"line":152},[32,978,979],{"class":228},"  final",[32,981,982],{"class":235}," jsObj ",[32,984,853],{"class":228},[32,986,987],{"class":235}," {",[32,989,990],{"class":61},"'name'",[32,992,993],{"class":228},":",[32,995,996],{"class":61}," 'Alice'",[32,998,905],{"class":235},[32,1000,1001],{"class":61},"'age'",[32,1003,993],{"class":228},[32,1005,1006],{"class":110}," 30",[32,1008,1009],{"class":235},"}.",[32,1011,1012],{"class":57},"jsify",[32,1014,1015],{"class":235},"() ",[32,1017,1018],{"class":228},"as",[32,1020,410],{"class":110},[32,1022,236],{"class":235},[32,1024,1025,1027,1030,1032,1035,1038,1040,1042,1045,1047,1049,1051,1054],{"class":34,"line":158},[32,1026,979],{"class":228},[32,1028,1029],{"class":235}," dartMap ",[32,1031,853],{"class":228},[32,1033,1034],{"class":235}," jsObj.",[32,1036,1037],{"class":57},"dartify",[32,1039,1015],{"class":235},[32,1041,1018],{"class":228},[32,1043,1044],{"class":110}," Map",[32,1046,392],{"class":235},[32,1048,303],{"class":110},[32,1050,905],{"class":235},[32,1052,1053],{"class":110},"dynamic",[32,1055,1056],{"class":235},">;\n",[32,1058,1059],{"class":34,"line":164},[32,1060,78],{"emptyLinePlaceholder":77},[32,1062,1063],{"class":34,"line":181},[32,1064,1065],{"class":38},"  \u002F\u002F Number → JSNumber and back\n",[32,1067,1068,1071,1074,1076,1079],{"class":34,"line":186},[32,1069,1070],{"class":110},"  JSNumber",[32,1072,1073],{"class":235}," jsNum ",[32,1075,853],{"class":228},[32,1077,1078],{"class":110}," 42.",[32,1080,1081],{"class":235},"toJS;\n",[32,1083,1084,1087,1090,1092],{"class":34,"line":192},[32,1085,1086],{"class":110},"  int",[32,1088,1089],{"class":235}," dartInt ",[32,1091,853],{"class":228},[32,1093,1094],{"class":235}," jsNum.toDartInt;\n",[32,1096,1097,1100,1103,1105],{"class":34,"line":198},[32,1098,1099],{"class":110},"  double",[32,1101,1102],{"class":235}," dartDouble ",[32,1104,853],{"class":228},[32,1106,1107],{"class":235}," jsNum.toDartDouble;\n",[32,1109,1110],{"class":34,"line":204},[32,1111,78],{"emptyLinePlaceholder":77},[32,1113,1114],{"class":34,"line":488},[32,1115,1116],{"class":38},"  \u002F\u002F bool → JSBoolean and back\n",[32,1118,1119,1122,1125,1127,1130],{"class":34,"line":493},[32,1120,1121],{"class":110},"  JSBoolean",[32,1123,1124],{"class":235}," jsBool ",[32,1126,853],{"class":228},[32,1128,1129],{"class":110}," true",[32,1131,859],{"class":235},[32,1133,1134,1137,1140,1142],{"class":34,"line":498},[32,1135,1136],{"class":110},"  bool",[32,1138,1139],{"class":235}," dartBool ",[32,1141,853],{"class":228},[32,1143,1144],{"class":235}," jsBool.toDart;\n",[32,1146,1147],{"class":34,"line":522},[32,1148,358],{"class":235},[32,1150,1151],{"class":34,"line":542},[32,1152,78],{"emptyLinePlaceholder":77},[32,1154,1155],{"class":34,"line":556},[32,1156,1157],{"class":38},"\u002F\u002F ❌ Anti-pattern: using `dynamic` for JS interop (no type safety).\n",[32,1159,1160],{"class":34,"line":572},[32,1161,1162],{"class":38},"\u002F\u002F dynamic x = someJsObject;\n",[32,1164,1165,1168],{"class":34,"line":577},[32,1166,1167],{"class":38},"\u002F\u002F x.anything();",[32,1169,1170],{"class":38},"  \u002F\u002F compiles, throws at runtime if method doesn't exist\n",[32,1172,1173],{"class":34,"line":582},[32,1174,78],{"emptyLinePlaceholder":77},[32,1176,1177],{"class":34,"line":588},[32,1178,1179],{"class":38},"\u002F\u002F ✓ Correct: use extension types for typed JS interop.\n",[14,1181,1183],{"id":1182},"conditional-imports-platform-abstraction","Conditional Imports — Platform Abstraction",[19,1185,1186],{"language":58},[23,1187,1189],{"className":220,"code":1188,"language":58,"meta":27,"style":27},"\u002F\u002F ── The pattern: a public file that conditionally re-exports ──\n\u002F\u002F storage.dart (public API)\nexport 'storage_io.dart'       \u002F\u002F native\n    if (dart.library.html) 'storage_web.dart';  \u002F\u002F web\n\n\u002F\u002F storage_io.dart (native — uses dart:io File)\nimport 'dart:io';\n\nclass Storage {\n  final File _file;\n  Storage(this._file);\n\n  Future\u003CString> read() => _file.readAsString();\n  Future\u003Cvoid> write(String data) => _file.writeAsString(data);\n}\n\n\u002F\u002F storage_web.dart (web — uses localStorage via dart:html)\nimport 'dart:html';\n\nclass Storage {\n  final String _key;\n  Storage(this._key);\n\n  Future\u003CString> read() async => window.localStorage[_key] ?? '';\n  Future\u003Cvoid> write(String data) async {\n    window.localStorage[_key] = data;\n  }\n}\n\n\u002F\u002F ── Both implementations must export the SAME public API ──\n\u002F\u002F (Same class names, method signatures, return types.)\n\u002F\u002F The compiler picks the right one at compile time — zero runtime cost.\n",[29,1190,1191,1196,1201,1212,1229,1233,1238,1247,1251,1261,1271,1284,1288,1314,1344,1348,1352,1357,1366,1370,1378,1388,1399,1403,1434,1456,1466,1471,1475,1479,1484,1489],{"__ignoreMap":27},[32,1192,1193],{"class":34,"line":35},[32,1194,1195],{"class":38},"\u002F\u002F ── The pattern: a public file that conditionally re-exports ──\n",[32,1197,1198],{"class":34,"line":42},[32,1199,1200],{"class":38},"\u002F\u002F storage.dart (public API)\n",[32,1202,1203,1206,1209],{"class":34,"line":48},[32,1204,1205],{"class":228},"export",[32,1207,1208],{"class":61}," 'storage_io.dart'",[32,1210,1211],{"class":38},"       \u002F\u002F native\n",[32,1213,1214,1217,1220,1223,1226],{"class":34,"line":54},[32,1215,1216],{"class":228},"    if",[32,1218,1219],{"class":235}," (dart.library.html) ",[32,1221,1222],{"class":61},"'storage_web.dart'",[32,1224,1225],{"class":235},";  ",[32,1227,1228],{"class":38},"\u002F\u002F web\n",[32,1230,1231],{"class":34,"line":74},[32,1232,78],{"emptyLinePlaceholder":77},[32,1234,1235],{"class":34,"line":81},[32,1236,1237],{"class":38},"\u002F\u002F storage_io.dart (native — uses dart:io File)\n",[32,1239,1240,1242,1245],{"class":34,"line":87},[32,1241,229],{"class":228},[32,1243,1244],{"class":61}," 'dart:io'",[32,1246,236],{"class":235},[32,1248,1249],{"class":34,"line":93},[32,1250,78],{"emptyLinePlaceholder":77},[32,1252,1253,1256,1259],{"class":34,"line":99},[32,1254,1255],{"class":228},"class",[32,1257,1258],{"class":110}," Storage",[32,1260,413],{"class":235},[32,1262,1263,1265,1268],{"class":34,"line":123},[32,1264,979],{"class":228},[32,1266,1267],{"class":110}," File",[32,1269,1270],{"class":235}," _file;\n",[32,1272,1273,1276,1278,1281],{"class":34,"line":129},[32,1274,1275],{"class":110},"  Storage",[32,1277,253],{"class":235},[32,1279,1280],{"class":110},"this",[32,1282,1283],{"class":235},"._file);\n",[32,1285,1286],{"class":34,"line":135},[32,1287,78],{"emptyLinePlaceholder":77},[32,1289,1290,1293,1295,1297,1299,1302,1304,1306,1309,1312],{"class":34,"line":141},[32,1291,1292],{"class":110},"  Future",[32,1294,392],{"class":235},[32,1296,303],{"class":110},[32,1298,430],{"class":235},[32,1300,1301],{"class":57},"read",[32,1303,1015],{"class":235},[32,1305,925],{"class":228},[32,1307,1308],{"class":235}," _file.",[32,1310,1311],{"class":57},"readAsString",[32,1313,273],{"class":235},[32,1315,1316,1318,1320,1322,1324,1327,1329,1331,1334,1336,1338,1341],{"class":34,"line":146},[32,1317,1292],{"class":110},[32,1319,392],{"class":235},[32,1321,315],{"class":228},[32,1323,430],{"class":235},[32,1325,1326],{"class":57},"write",[32,1328,253],{"class":235},[32,1330,303],{"class":110},[32,1332,1333],{"class":235}," data) ",[32,1335,925],{"class":228},[32,1337,1308],{"class":235},[32,1339,1340],{"class":57},"writeAsString",[32,1342,1343],{"class":235},"(data);\n",[32,1345,1346],{"class":34,"line":152},[32,1347,358],{"class":235},[32,1349,1350],{"class":34,"line":158},[32,1351,78],{"emptyLinePlaceholder":77},[32,1353,1354],{"class":34,"line":164},[32,1355,1356],{"class":38},"\u002F\u002F storage_web.dart (web — uses localStorage via dart:html)\n",[32,1358,1359,1361,1364],{"class":34,"line":181},[32,1360,229],{"class":228},[32,1362,1363],{"class":61}," 'dart:html'",[32,1365,236],{"class":235},[32,1367,1368],{"class":34,"line":186},[32,1369,78],{"emptyLinePlaceholder":77},[32,1371,1372,1374,1376],{"class":34,"line":192},[32,1373,1255],{"class":228},[32,1375,1258],{"class":110},[32,1377,413],{"class":235},[32,1379,1380,1382,1385],{"class":34,"line":198},[32,1381,979],{"class":228},[32,1383,1384],{"class":110}," String",[32,1386,1387],{"class":235}," _key;\n",[32,1389,1390,1392,1394,1396],{"class":34,"line":204},[32,1391,1275],{"class":110},[32,1393,253],{"class":235},[32,1395,1280],{"class":110},[32,1397,1398],{"class":235},"._key);\n",[32,1400,1401],{"class":34,"line":488},[32,1402,78],{"emptyLinePlaceholder":77},[32,1404,1405,1407,1409,1411,1413,1415,1417,1420,1423,1426,1429,1432],{"class":34,"line":493},[32,1406,1292],{"class":110},[32,1408,392],{"class":235},[32,1410,303],{"class":110},[32,1412,430],{"class":235},[32,1414,1301],{"class":57},[32,1416,1015],{"class":235},[32,1418,1419],{"class":228},"async",[32,1421,1422],{"class":228}," =>",[32,1424,1425],{"class":235}," window.localStorage[_key] ",[32,1427,1428],{"class":228},"??",[32,1430,1431],{"class":61}," ''",[32,1433,236],{"class":235},[32,1435,1436,1438,1440,1442,1444,1446,1448,1450,1452,1454],{"class":34,"line":498},[32,1437,1292],{"class":110},[32,1439,392],{"class":235},[32,1441,315],{"class":228},[32,1443,430],{"class":235},[32,1445,1326],{"class":57},[32,1447,253],{"class":235},[32,1449,303],{"class":110},[32,1451,1333],{"class":235},[32,1453,1419],{"class":228},[32,1455,413],{"class":235},[32,1457,1458,1461,1463],{"class":34,"line":522},[32,1459,1460],{"class":235},"    window.localStorage[_key] ",[32,1462,853],{"class":228},[32,1464,1465],{"class":235}," data;\n",[32,1467,1468],{"class":34,"line":542},[32,1469,1470],{"class":235},"  }\n",[32,1472,1473],{"class":34,"line":556},[32,1474,358],{"class":235},[32,1476,1477],{"class":34,"line":572},[32,1478,78],{"emptyLinePlaceholder":77},[32,1480,1481],{"class":34,"line":577},[32,1482,1483],{"class":38},"\u002F\u002F ── Both implementations must export the SAME public API ──\n",[32,1485,1486],{"class":34,"line":582},[32,1487,1488],{"class":38},"\u002F\u002F (Same class names, method signatures, return types.)\n",[32,1490,1491],{"class":34,"line":588},[32,1492,1493],{"class":38},"\u002F\u002F The compiler picks the right one at compile time — zero runtime cost.\n",[798,1495,1497],{"id":1496},"cross-platform-http","Cross-Platform HTTP",[19,1499,1500],{"language":58},[23,1501,1503],{"className":220,"code":1502,"language":58,"meta":27,"style":27},"\u002F\u002F The `http` package abstracts the platform — uses fetch on web,\n\u002F\u002F HttpClient on native. No conditional imports needed for basic HTTP.\n\nimport 'package:http\u002Fhttp.dart' as http;\n\nFuture\u003CMap\u003CString, dynamic>> fetchJson(String url) async {\n  final response = await http.get(Uri.parse(url));\n  if (response.statusCode != 200) {\n    throw HttpException('HTTP ${response.statusCode}', uri: Uri.parse(url));\n  }\n  return jsonDecode(response.body) as Map\u003CString, dynamic>;\n}\n\n\u002F\u002F This works on BOTH web and native — the `http` package handles it.\n\u002F\u002F For advanced features (interceptors, cancellation), use `dio`.\n",[29,1504,1505,1510,1515,1519,1532,1536,1571,1603,1620,1664,1668,1693,1697,1701,1706],{"__ignoreMap":27},[32,1506,1507],{"class":34,"line":35},[32,1508,1509],{"class":38},"\u002F\u002F The `http` package abstracts the platform — uses fetch on web,\n",[32,1511,1512],{"class":34,"line":42},[32,1513,1514],{"class":38},"\u002F\u002F HttpClient on native. No conditional imports needed for basic HTTP.\n",[32,1516,1517],{"class":34,"line":48},[32,1518,78],{"emptyLinePlaceholder":77},[32,1520,1521,1523,1526,1529],{"class":34,"line":54},[32,1522,229],{"class":228},[32,1524,1525],{"class":61}," 'package:http\u002Fhttp.dart'",[32,1527,1528],{"class":228}," as",[32,1530,1531],{"class":235}," http;\n",[32,1533,1534],{"class":34,"line":74},[32,1535,78],{"emptyLinePlaceholder":77},[32,1537,1538,1541,1543,1546,1548,1550,1552,1554,1557,1560,1562,1564,1567,1569],{"class":34,"line":81},[32,1539,1540],{"class":110},"Future",[32,1542,392],{"class":235},[32,1544,1545],{"class":110},"Map",[32,1547,392],{"class":235},[32,1549,303],{"class":110},[32,1551,905],{"class":235},[32,1553,1053],{"class":110},[32,1555,1556],{"class":235},">> ",[32,1558,1559],{"class":57},"fetchJson",[32,1561,253],{"class":235},[32,1563,303],{"class":110},[32,1565,1566],{"class":235}," url) ",[32,1568,1419],{"class":228},[32,1570,413],{"class":235},[32,1572,1573,1575,1578,1580,1583,1586,1589,1591,1594,1597,1600],{"class":34,"line":87},[32,1574,979],{"class":228},[32,1576,1577],{"class":235}," response ",[32,1579,853],{"class":228},[32,1581,1582],{"class":228}," await",[32,1584,1585],{"class":235}," http.",[32,1587,1588],{"class":57},"get",[32,1590,253],{"class":235},[32,1592,1593],{"class":110},"Uri",[32,1595,1596],{"class":235},".",[32,1598,1599],{"class":57},"parse",[32,1601,1602],{"class":235},"(url));\n",[32,1604,1605,1608,1611,1614,1617],{"class":34,"line":93},[32,1606,1607],{"class":228},"  if",[32,1609,1610],{"class":235}," (response.statusCode ",[32,1612,1613],{"class":228},"!=",[32,1615,1616],{"class":110}," 200",[32,1618,1619],{"class":235},") {\n",[32,1621,1622,1625,1628,1630,1633,1636,1639,1641,1644,1647,1650,1653,1655,1658,1660,1662],{"class":34,"line":99},[32,1623,1624],{"class":228},"    throw",[32,1626,1627],{"class":110}," HttpException",[32,1629,253],{"class":235},[32,1631,1632],{"class":61},"'HTTP ",[32,1634,1635],{"class":61},"${",[32,1637,1638],{"class":110},"response",[32,1640,1596],{"class":61},[32,1642,1643],{"class":110},"statusCode",[32,1645,1646],{"class":61},"}",[32,1648,1649],{"class":61},"'",[32,1651,1652],{"class":235},", uri",[32,1654,993],{"class":228},[32,1656,1657],{"class":110}," Uri",[32,1659,1596],{"class":235},[32,1661,1599],{"class":57},[32,1663,1602],{"class":235},[32,1665,1666],{"class":34,"line":123},[32,1667,1470],{"class":235},[32,1669,1670,1673,1676,1679,1681,1683,1685,1687,1689,1691],{"class":34,"line":129},[32,1671,1672],{"class":228},"  return",[32,1674,1675],{"class":57}," jsonDecode",[32,1677,1678],{"class":235},"(response.body) ",[32,1680,1018],{"class":228},[32,1682,1044],{"class":110},[32,1684,392],{"class":235},[32,1686,303],{"class":110},[32,1688,905],{"class":235},[32,1690,1053],{"class":110},[32,1692,1056],{"class":235},[32,1694,1695],{"class":34,"line":135},[32,1696,358],{"class":235},[32,1698,1699],{"class":34,"line":141},[32,1700,78],{"emptyLinePlaceholder":77},[32,1702,1703],{"class":34,"line":146},[32,1704,1705],{"class":38},"\u002F\u002F This works on BOTH web and native — the `http` package handles it.\n",[32,1707,1708],{"class":34,"line":152},[32,1709,1710],{"class":38},"\u002F\u002F For advanced features (interceptors, cancellation), use `dio`.\n",[14,1712,1714],{"id":1713},"web-platform-limitations","Web Platform Limitations",[19,1716,1717],{"language":58},[23,1718,1720],{"className":220,"code":1719,"language":58,"meta":27,"style":27},"\u002F\u002F ── 1. `int` is a JS double on web ──\n\u002F\u002F Native: int is 64-bit. Web: int is IEEE 754 double — precision lost above 2^53.\n\u002F\u002F On native:\nprint(9007199254740993);  \u002F\u002F 9007199254740993 (exact)\n\u002F\u002F On web:\nprint(9007199254740993);  \u002F\u002F 9007199254740992 (rounded — can't represent 2^53+1)\n\n\u002F\u002F Fix: use BigInt for large integers on web.\nfinal big = BigInt.parse('9007199254740993');\nprint(big);  \u002F\u002F exact on all platforms\n\n\u002F\u002F ── 2. No `dart:io` on web ──\n\u002F\u002F File, HttpClient (server), Platform.exit, Process — all native-only.\n\u002F\u002F import 'dart:io';  \u002F\u002F ✗ compile error on web\n\u002F\u002F Use dart:html, fetch, or the http package instead.\n\n\u002F\u002F ── 3. No isolates on web ──\n\u002F\u002F Dart on web is single-threaded. Isolate.run throws or runs on main thread.\n\u002F\u002F For CPU-heavy work on web, use Web Workers (via JS interop).\n\u002F\u002F await Isolate.run(() => heavy());  \u002F\u002F ✗ may throw on web\n\n\u002F\u002F ── 4. No `dart:mirrors` on web\u002FAOT ──\n\u002F\u002F Runtime reflection is unsupported in dart2js and AOT.\n\u002F\u002F import 'dart:mirrors';  \u002F\u002F ✗ compile error on web\n\u002F\u002F Use code generation (json_serializable, freezed) instead of reflection.\n",[29,1721,1722,1727,1732,1737,1752,1757,1770,1774,1779,1804,1814,1818,1823,1828,1836,1841,1845,1850,1855,1860,1868,1872,1877,1882,1889],{"__ignoreMap":27},[32,1723,1724],{"class":34,"line":35},[32,1725,1726],{"class":38},"\u002F\u002F ── 1. `int` is a JS double on web ──\n",[32,1728,1729],{"class":34,"line":42},[32,1730,1731],{"class":38},"\u002F\u002F Native: int is 64-bit. Web: int is IEEE 754 double — precision lost above 2^53.\n",[32,1733,1734],{"class":34,"line":48},[32,1735,1736],{"class":38},"\u002F\u002F On native:\n",[32,1738,1739,1742,1744,1747,1749],{"class":34,"line":54},[32,1740,1741],{"class":57},"print",[32,1743,253],{"class":235},[32,1745,1746],{"class":110},"9007199254740993",[32,1748,334],{"class":235},[32,1750,1751],{"class":38},"\u002F\u002F 9007199254740993 (exact)\n",[32,1753,1754],{"class":34,"line":74},[32,1755,1756],{"class":38},"\u002F\u002F On web:\n",[32,1758,1759,1761,1763,1765,1767],{"class":34,"line":81},[32,1760,1741],{"class":57},[32,1762,253],{"class":235},[32,1764,1746],{"class":110},[32,1766,334],{"class":235},[32,1768,1769],{"class":38},"\u002F\u002F 9007199254740992 (rounded — can't represent 2^53+1)\n",[32,1771,1772],{"class":34,"line":87},[32,1773,78],{"emptyLinePlaceholder":77},[32,1775,1776],{"class":34,"line":93},[32,1777,1778],{"class":38},"\u002F\u002F Fix: use BigInt for large integers on web.\n",[32,1780,1781,1784,1787,1789,1792,1794,1796,1798,1801],{"class":34,"line":99},[32,1782,1783],{"class":228},"final",[32,1785,1786],{"class":235}," big ",[32,1788,853],{"class":228},[32,1790,1791],{"class":110}," BigInt",[32,1793,1596],{"class":235},[32,1795,1599],{"class":57},[32,1797,253],{"class":235},[32,1799,1800],{"class":61},"'9007199254740993'",[32,1802,1803],{"class":235},");\n",[32,1805,1806,1808,1811],{"class":34,"line":123},[32,1807,1741],{"class":57},[32,1809,1810],{"class":235},"(big);  ",[32,1812,1813],{"class":38},"\u002F\u002F exact on all platforms\n",[32,1815,1816],{"class":34,"line":129},[32,1817,78],{"emptyLinePlaceholder":77},[32,1819,1820],{"class":34,"line":135},[32,1821,1822],{"class":38},"\u002F\u002F ── 2. No `dart:io` on web ──\n",[32,1824,1825],{"class":34,"line":141},[32,1826,1827],{"class":38},"\u002F\u002F File, HttpClient (server), Platform.exit, Process — all native-only.\n",[32,1829,1830,1833],{"class":34,"line":146},[32,1831,1832],{"class":38},"\u002F\u002F import 'dart:io';",[32,1834,1835],{"class":38},"  \u002F\u002F ✗ compile error on web\n",[32,1837,1838],{"class":34,"line":152},[32,1839,1840],{"class":38},"\u002F\u002F Use dart:html, fetch, or the http package instead.\n",[32,1842,1843],{"class":34,"line":158},[32,1844,78],{"emptyLinePlaceholder":77},[32,1846,1847],{"class":34,"line":164},[32,1848,1849],{"class":38},"\u002F\u002F ── 3. No isolates on web ──\n",[32,1851,1852],{"class":34,"line":181},[32,1853,1854],{"class":38},"\u002F\u002F Dart on web is single-threaded. Isolate.run throws or runs on main thread.\n",[32,1856,1857],{"class":34,"line":186},[32,1858,1859],{"class":38},"\u002F\u002F For CPU-heavy work on web, use Web Workers (via JS interop).\n",[32,1861,1862,1865],{"class":34,"line":192},[32,1863,1864],{"class":38},"\u002F\u002F await Isolate.run(() => heavy());",[32,1866,1867],{"class":38},"  \u002F\u002F ✗ may throw on web\n",[32,1869,1870],{"class":34,"line":198},[32,1871,78],{"emptyLinePlaceholder":77},[32,1873,1874],{"class":34,"line":204},[32,1875,1876],{"class":38},"\u002F\u002F ── 4. No `dart:mirrors` on web\u002FAOT ──\n",[32,1878,1879],{"class":34,"line":488},[32,1880,1881],{"class":38},"\u002F\u002F Runtime reflection is unsupported in dart2js and AOT.\n",[32,1883,1884,1887],{"class":34,"line":493},[32,1885,1886],{"class":38},"\u002F\u002F import 'dart:mirrors';",[32,1888,1835],{"class":38},[32,1890,1891],{"class":34,"line":498},[32,1892,1893],{"class":38},"\u002F\u002F Use code generation (json_serializable, freezed) instead of reflection.\n",[14,1895,1897,1898],{"id":1896},"dom-access-darthtml","DOM Access — ",[29,1899,1900],{},"dart:html",[19,1902,1903],{"language":58},[23,1904,1906],{"className":220,"code":1905,"language":58,"meta":27,"style":27},"import 'dart:html';\n\nvoid main() {\n  \u002F\u002F ── Querying the DOM ──\n  final button = querySelector('#myButton')!;  \u002F\u002F null if not found — use `!` or check\n  final items = querySelectorAll('.item');  \u002F\u002F ElementList (iterable)\n\n  \u002F\u002F ── Creating elements ──\n  final div = DivElement()\n    ..text = 'Hello, Dart!'  \u002F\u002F set text\n    ..classes.add('greeting')  \u002F\u002F add CSS class\n    ..style.color = 'blue';  \u002F\u002F inline style\n  document.body!.append(div);\n\n  \u002F\u002F ── Events are Streams ──\n  button.onClick.listen((MouseEvent e) {\n    print('Button clicked at (${e.clientX}, ${e.clientY})');\n  });\n\n  input.onInput.listen((Event e) {\n    print('Input changed: ${input.value}');\n  });\n\n  window.onResize.listen((_) {\n    print('Window resized to ${window.innerWidth}x${window.innerHeight}');\n  });\n\n  \u002F\u002F ── Cancel subscriptions to avoid memory leaks ──\n  final sub = button.onClick.listen((_) => handleClick());\n  \u002F\u002F Later (cleanup):\n  sub.cancel();  \u002F\u002F ← MUST cancel, or the listener leaks\n\n  \u002F\u002F ── HTTP on web (low-level) ──\n  final response = await HttpRequest.getString('https:\u002F\u002Fapi.example.com\u002Fdata');\n  print(response);\n}\n",[29,1907,1908,1916,1920,1928,1933,1961,1983,1987,1992,2007,2020,2039,2054,2069,2073,2078,2095,2135,2139,2143,2157,2182,2186,2190,2200,2239,2243,2247,2252,2277,2282,2296,2300,2305,2330,2337],{"__ignoreMap":27},[32,1909,1910,1912,1914],{"class":34,"line":35},[32,1911,229],{"class":228},[32,1913,1363],{"class":61},[32,1915,236],{"class":235},[32,1917,1918],{"class":34,"line":42},[32,1919,78],{"emptyLinePlaceholder":77},[32,1921,1922,1924,1926],{"class":34,"line":48},[32,1923,315],{"class":228},[32,1925,318],{"class":57},[32,1927,321],{"class":235},[32,1929,1930],{"class":34,"line":54},[32,1931,1932],{"class":38},"  \u002F\u002F ── Querying the DOM ──\n",[32,1934,1935,1937,1940,1942,1945,1947,1950,1953,1956,1958],{"class":34,"line":74},[32,1936,979],{"class":228},[32,1938,1939],{"class":235}," button ",[32,1941,853],{"class":228},[32,1943,1944],{"class":57}," querySelector",[32,1946,253],{"class":235},[32,1948,1949],{"class":61},"'#myButton'",[32,1951,1952],{"class":235},")",[32,1954,1955],{"class":228},"!",[32,1957,1225],{"class":235},[32,1959,1960],{"class":38},"\u002F\u002F null if not found — use `!` or check\n",[32,1962,1963,1965,1968,1970,1973,1975,1978,1980],{"class":34,"line":81},[32,1964,979],{"class":228},[32,1966,1967],{"class":235}," items ",[32,1969,853],{"class":228},[32,1971,1972],{"class":57}," querySelectorAll",[32,1974,253],{"class":235},[32,1976,1977],{"class":61},"'.item'",[32,1979,334],{"class":235},[32,1981,1982],{"class":38},"\u002F\u002F ElementList (iterable)\n",[32,1984,1985],{"class":34,"line":87},[32,1986,78],{"emptyLinePlaceholder":77},[32,1988,1989],{"class":34,"line":93},[32,1990,1991],{"class":38},"  \u002F\u002F ── Creating elements ──\n",[32,1993,1994,1996,1999,2001,2004],{"class":34,"line":99},[32,1995,979],{"class":228},[32,1997,1998],{"class":235}," div ",[32,2000,853],{"class":228},[32,2002,2003],{"class":110}," DivElement",[32,2005,2006],{"class":235},"()\n",[32,2008,2009,2012,2014,2017],{"class":34,"line":123},[32,2010,2011],{"class":235},"    ..text ",[32,2013,853],{"class":228},[32,2015,2016],{"class":61}," 'Hello, Dart!'",[32,2018,2019],{"class":38},"  \u002F\u002F set text\n",[32,2021,2022,2025,2028,2030,2033,2036],{"class":34,"line":129},[32,2023,2024],{"class":235},"    ..classes.",[32,2026,2027],{"class":57},"add",[32,2029,253],{"class":235},[32,2031,2032],{"class":61},"'greeting'",[32,2034,2035],{"class":235},")  ",[32,2037,2038],{"class":38},"\u002F\u002F add CSS class\n",[32,2040,2041,2044,2046,2049,2051],{"class":34,"line":135},[32,2042,2043],{"class":235},"    ..style.color ",[32,2045,853],{"class":228},[32,2047,2048],{"class":61}," 'blue'",[32,2050,1225],{"class":235},[32,2052,2053],{"class":38},"\u002F\u002F inline style\n",[32,2055,2056,2059,2061,2063,2066],{"class":34,"line":141},[32,2057,2058],{"class":235},"  document.body",[32,2060,1955],{"class":228},[32,2062,1596],{"class":235},[32,2064,2065],{"class":57},"append",[32,2067,2068],{"class":235},"(div);\n",[32,2070,2071],{"class":34,"line":146},[32,2072,78],{"emptyLinePlaceholder":77},[32,2074,2075],{"class":34,"line":152},[32,2076,2077],{"class":38},"  \u002F\u002F ── Events are Streams ──\n",[32,2079,2080,2083,2086,2089,2092],{"class":34,"line":158},[32,2081,2082],{"class":235},"  button.onClick.",[32,2084,2085],{"class":57},"listen",[32,2087,2088],{"class":235},"((",[32,2090,2091],{"class":110},"MouseEvent",[32,2093,2094],{"class":235}," e) {\n",[32,2096,2097,2100,2102,2105,2107,2110,2112,2115,2117,2119,2121,2123,2125,2128,2130,2133],{"class":34,"line":164},[32,2098,2099],{"class":57},"    print",[32,2101,253],{"class":235},[32,2103,2104],{"class":61},"'Button clicked at (",[32,2106,1635],{"class":61},[32,2108,2109],{"class":110},"e",[32,2111,1596],{"class":61},[32,2113,2114],{"class":110},"clientX",[32,2116,1646],{"class":61},[32,2118,905],{"class":61},[32,2120,1635],{"class":61},[32,2122,2109],{"class":110},[32,2124,1596],{"class":61},[32,2126,2127],{"class":110},"clientY",[32,2129,1646],{"class":61},[32,2131,2132],{"class":61},")'",[32,2134,1803],{"class":235},[32,2136,2137],{"class":34,"line":181},[32,2138,724],{"class":235},[32,2140,2141],{"class":34,"line":186},[32,2142,78],{"emptyLinePlaceholder":77},[32,2144,2145,2148,2150,2152,2155],{"class":34,"line":192},[32,2146,2147],{"class":235},"  input.onInput.",[32,2149,2085],{"class":57},[32,2151,2088],{"class":235},[32,2153,2154],{"class":110},"Event",[32,2156,2094],{"class":235},[32,2158,2159,2161,2163,2166,2168,2171,2173,2176,2178,2180],{"class":34,"line":198},[32,2160,2099],{"class":57},[32,2162,253],{"class":235},[32,2164,2165],{"class":61},"'Input changed: ",[32,2167,1635],{"class":61},[32,2169,2170],{"class":110},"input",[32,2172,1596],{"class":61},[32,2174,2175],{"class":110},"value",[32,2177,1646],{"class":61},[32,2179,1649],{"class":61},[32,2181,1803],{"class":235},[32,2183,2184],{"class":34,"line":204},[32,2185,724],{"class":235},[32,2187,2188],{"class":34,"line":488},[32,2189,78],{"emptyLinePlaceholder":77},[32,2191,2192,2195,2197],{"class":34,"line":493},[32,2193,2194],{"class":235},"  window.onResize.",[32,2196,2085],{"class":57},[32,2198,2199],{"class":235},"((_) {\n",[32,2201,2202,2204,2206,2209,2211,2214,2216,2219,2221,2224,2226,2228,2230,2233,2235,2237],{"class":34,"line":498},[32,2203,2099],{"class":57},[32,2205,253],{"class":235},[32,2207,2208],{"class":61},"'Window resized to ",[32,2210,1635],{"class":61},[32,2212,2213],{"class":110},"window",[32,2215,1596],{"class":61},[32,2217,2218],{"class":110},"innerWidth",[32,2220,1646],{"class":61},[32,2222,2223],{"class":61},"x",[32,2225,1635],{"class":61},[32,2227,2213],{"class":110},[32,2229,1596],{"class":61},[32,2231,2232],{"class":110},"innerHeight",[32,2234,1646],{"class":61},[32,2236,1649],{"class":61},[32,2238,1803],{"class":235},[32,2240,2241],{"class":34,"line":522},[32,2242,724],{"class":235},[32,2244,2245],{"class":34,"line":542},[32,2246,78],{"emptyLinePlaceholder":77},[32,2248,2249],{"class":34,"line":556},[32,2250,2251],{"class":38},"  \u002F\u002F ── Cancel subscriptions to avoid memory leaks ──\n",[32,2253,2254,2256,2259,2261,2264,2266,2269,2271,2274],{"class":34,"line":572},[32,2255,979],{"class":228},[32,2257,2258],{"class":235}," sub ",[32,2260,853],{"class":228},[32,2262,2263],{"class":235}," button.onClick.",[32,2265,2085],{"class":57},[32,2267,2268],{"class":235},"((_) ",[32,2270,925],{"class":228},[32,2272,2273],{"class":57}," handleClick",[32,2275,2276],{"class":235},"());\n",[32,2278,2279],{"class":34,"line":577},[32,2280,2281],{"class":38},"  \u002F\u002F Later (cleanup):\n",[32,2283,2284,2287,2290,2293],{"class":34,"line":582},[32,2285,2286],{"class":235},"  sub.",[32,2288,2289],{"class":57},"cancel",[32,2291,2292],{"class":235},"();  ",[32,2294,2295],{"class":38},"\u002F\u002F ← MUST cancel, or the listener leaks\n",[32,2297,2298],{"class":34,"line":588},[32,2299,78],{"emptyLinePlaceholder":77},[32,2301,2302],{"class":34,"line":600},[32,2303,2304],{"class":38},"  \u002F\u002F ── HTTP on web (low-level) ──\n",[32,2306,2307,2309,2311,2313,2315,2318,2320,2323,2325,2328],{"class":34,"line":621},[32,2308,979],{"class":228},[32,2310,1577],{"class":235},[32,2312,853],{"class":228},[32,2314,1582],{"class":228},[32,2316,2317],{"class":110}," HttpRequest",[32,2319,1596],{"class":235},[32,2321,2322],{"class":57},"getString",[32,2324,253],{"class":235},[32,2326,2327],{"class":61},"'https:\u002F\u002Fapi.example.com\u002Fdata'",[32,2329,1803],{"class":235},[32,2331,2332,2334],{"class":34,"line":644},[32,2333,342],{"class":57},[32,2335,2336],{"class":235},"(response);\n",[32,2338,2339],{"class":34,"line":656},[32,2340,358],{"class":235},[14,2342,2344],{"id":2343},"tips-tricks","💡 Tips & Tricks",[2346,2347,2348,2379,2388,2403,2433],"ul",{},[2349,2350,2351,2355,2356,2359,2360,2363,2364,2367,2368,2371,2372,2375,2376,2378],"li",{},[2352,2353,2354],"strong",{},"Idiom",": use the ",[29,2357,2358],{},"http"," package (not ",[29,2361,2362],{},"dart:io","'s ",[29,2365,2366],{},"HttpClient",") for cross-platform HTTP — ",[29,2369,2370],{},"http.get"," works on both web (",[29,2373,2374],{},"fetch",") and native (",[29,2377,2366],{},"). Avoids platform conditionals for HTTP.",[2349,2380,2381,2383,2384,2387],{},[2352,2382,2354],{},": use conditional imports for platform-specific code — ",[29,2385,2386],{},"export 'web.dart' if (dart.library.io) 'io.dart';"," chooses the web or native implementation. The exported API must match. Clean for cross-platform packages.",[2349,2389,2390,2392,2393,2395,2396,2399,2400,2402],{},[2352,2391,2354],{},": use ",[29,2394,214],{}," + extension types (Dart 3.3+) for JS interop — ",[29,2397,2398],{},"@JS()"," declares JS functions, extension types wrap JS objects with typed interfaces. Safer than ",[29,2401,1053],{}," interop. Use for calling JS libraries.",[2349,2404,2405,2392,2407,2410,2411,2414,2415,2418,2419,2410,2421,2424,2425,2428,2429,2432],{},[2352,2406,2354],{},[29,2408,2409],{},"jsonDecode","\u002F",[29,2412,2413],{},"jsonEncode"," (from ",[29,2416,2417],{},"dart:convert",") for JSON — returns ",[29,2420,1053],{},[29,2422,2423],{},"Map\u003CString, dynamic>",". Cast carefully (",[29,2426,2427],{},"as Type?"," then handle null). For typed JSON, use ",[29,2430,2431],{},"json_serializable"," (code generation).",[2349,2434,2435,2392,2438,2441,2442,2444,2445,2447],{},[2352,2436,2437],{},"Portability",[29,2439,2440],{},"BigInt"," for integers above 2^53 that must work on web — ",[29,2443,536],{}," on web is a JS double and loses precision. On native, ",[29,2446,536],{}," is 64-bit and safe up to 2^63-1.",[14,2449,2451],{"id":2450},"️-edge-cases-gotchas","⚠️ Edge Cases & Gotchas",[2346,2453,2454,2476,2492,2501,2520,2526,2549,2569,2583,2589],{},[2349,2455,2456,2461,2462,905,2465,2467,2468,2471,2472,2475],{},[2352,2457,2458,2460],{},[29,2459,2362],{}," doesn't work on web",": ",[29,2463,2464],{},"File",[29,2466,2366],{}," (server), ",[29,2469,2470],{},"Platform.exit"," are native-only. Use conditional imports (",[29,2473,2474],{},"if (dart.library.html)",") for cross-platform code.",[2349,2477,2478,2461,2483,2485,2486,2488,2489,2491],{},[2352,2479,2480,2482],{},[29,2481,536],{}," on web is a JS double",[29,2484,536],{}," values above 2^53 lose precision on web. For large integers, use ",[29,2487,2440],{}," or accept the limitation. On native, ",[29,2490,536],{}," is 64-bit.",[2349,2493,2494,2461,2497,2500],{},[2352,2495,2496],{},"No isolates on web",[29,2498,2499],{},"Isolate.run"," throws or runs on the main thread. The web is single-threaded. Use Web Workers (via JS interop) for parallelism.",[2349,2502,2503,2461,2510,2513,2514,905,2516,2519],{},[2352,2504,2505,2506,2509],{},"No ",[29,2507,2508],{},"dart:mirrors"," on web\u002FAOT",[29,2511,2512],{},"dart2js"," and AOT don't support runtime reflection. Use code generation (",[29,2515,2431],{},[29,2517,2518],{},"freezed",") instead of reflection.",[2349,2521,2522,2525],{},[2352,2523,2524],{},"DDC vs dart2js output differs",": DDC (dev) produces readable JS with runtime checks; dart2js (prod) produces minified JS with asserts stripped. Test with dart2js, not just DDC.",[2349,2527,2528,2461,2535,2538,2539,2541,2542,2544,2545,2548],{},[2352,2529,2530,2532,2533],{},[29,2531,2409],{}," returns ",[29,2534,1053],{},[29,2536,2537],{},"jsonDecode('{\"a\":1}')"," is ",[29,2540,2423],{}," but statically ",[29,2543,1053],{},". Cast: ",[29,2546,2547],{},"jsonDecode(s) as Map\u003CString, dynamic>",", then access.",[2349,2550,2551,2461,2558,2538,2561,2564,2565,2568],{},[2352,2552,2553,2554,2557],{},"Event listeners are ",[29,2555,2556],{},"Stream","s",[29,2559,2560],{},"button.onClick",[29,2562,2563],{},"Stream\u003CMouseEvent>",". Cancel subscriptions (",[29,2566,2567],{},"sub.cancel()",") to avoid memory leaks, especially in single-page apps.",[2349,2570,2571,2579,2580,2582],{},[2352,2572,2573,2532,2576],{},[29,2574,2575],{},"querySelector",[29,2577,2578],{},"Element?",": null if not found. Use ",[29,2581,1955],{}," (if certain) or check for null. Forgetting the null check is a common web bug.",[2349,2584,2585,2588],{},[2352,2586,2587],{},"Web Workers for parallelism",": Dart on web is single-threaded. For CPU-heavy work, use Web Workers (via JS interop) — not Dart isolates (which don't exist on web).",[2349,2590,2591,2594],{},[2352,2592,2593],{},"Flutter Web uses CanvasKit or HTML",": CanvasKit (Skia\u002FWasm) has better fidelity but larger bundle (~2MB). HTML renderer is smaller but less precise. Choose based on needs.",[14,2596,2598],{"id":2597},"spot-the-bug","🧠 Spot the Bug",[2600,2601,2602,2603,2605],"p",{},"A developer's cross-platform package uses ",[29,2604,2362],{}," directly for file storage. It works in dev but crashes in the web build:",[19,2607,2608],{"language":58},[23,2609,2611],{"className":220,"code":2610,"language":58,"meta":27,"style":27},"import 'dart:io';\n\nclass FileStorage {\n  final String path;\n  FileStorage(this.path);\n\n  Future\u003CString> read() => File(path).readAsString();\n  Future\u003Cvoid> write(String data) => File(path).writeAsString(data);\n}\n",[29,2612,2613,2621,2625,2634,2643,2655,2659,2684,2712],{"__ignoreMap":27},[32,2614,2615,2617,2619],{"class":34,"line":35},[32,2616,229],{"class":228},[32,2618,1244],{"class":61},[32,2620,236],{"class":235},[32,2622,2623],{"class":34,"line":42},[32,2624,78],{"emptyLinePlaceholder":77},[32,2626,2627,2629,2632],{"class":34,"line":48},[32,2628,1255],{"class":228},[32,2630,2631],{"class":110}," FileStorage",[32,2633,413],{"class":235},[32,2635,2636,2638,2640],{"class":34,"line":54},[32,2637,979],{"class":228},[32,2639,1384],{"class":110},[32,2641,2642],{"class":235}," path;\n",[32,2644,2645,2648,2650,2652],{"class":34,"line":74},[32,2646,2647],{"class":110},"  FileStorage",[32,2649,253],{"class":235},[32,2651,1280],{"class":110},[32,2653,2654],{"class":235},".path);\n",[32,2656,2657],{"class":34,"line":81},[32,2658,78],{"emptyLinePlaceholder":77},[32,2660,2661,2663,2665,2667,2669,2671,2673,2675,2677,2680,2682],{"class":34,"line":87},[32,2662,1292],{"class":110},[32,2664,392],{"class":235},[32,2666,303],{"class":110},[32,2668,430],{"class":235},[32,2670,1301],{"class":57},[32,2672,1015],{"class":235},[32,2674,925],{"class":228},[32,2676,1267],{"class":110},[32,2678,2679],{"class":235},"(path).",[32,2681,1311],{"class":57},[32,2683,273],{"class":235},[32,2685,2686,2688,2690,2692,2694,2696,2698,2700,2702,2704,2706,2708,2710],{"class":34,"line":93},[32,2687,1292],{"class":110},[32,2689,392],{"class":235},[32,2691,315],{"class":228},[32,2693,430],{"class":235},[32,2695,1326],{"class":57},[32,2697,253],{"class":235},[32,2699,303],{"class":110},[32,2701,1333],{"class":235},[32,2703,925],{"class":228},[32,2705,1267],{"class":110},[32,2707,2679],{"class":235},[32,2709,1340],{"class":57},[32,2711,1343],{"class":235},[32,2713,2714],{"class":34,"line":99},[32,2715,358],{"class":235},[2600,2717,2718],{},"How to make this cross-platform?",[2720,2721,2722,2726,2734,2737,2990,3007],"details",{},[2723,2724,2725],"summary",{},"Answer",[2600,2727,2728,2730,2731,2733],{},[29,2729,2362],{}," is native-only. Importing it in a web project fails at compile time (or the ",[29,2732,2464],{}," usage fails at runtime). The code can't run on the web as-is.",[2600,2735,2736],{},"The fix — use conditional imports to provide a web-specific implementation:",[23,2738,2740],{"className":220,"code":2739,"language":58,"meta":27,"style":27},"\u002F\u002F storage.dart (public API — conditional export)\nexport 'storage_io.dart'\n    if (dart.library.html) 'storage_web.dart';\n\n\u002F\u002F storage_io.dart (native — uses dart:io)\nimport 'dart:io';\n\nclass FileStorage {\n  final String path;\n  FileStorage(this.path);\n\n  Future\u003CString> read() => File(path).readAsString();\n  Future\u003Cvoid> write(String data) => File(path).writeAsString(data);\n}\n\n\u002F\u002F storage_web.dart (web — uses localStorage)\nimport 'dart:html';\n\nclass FileStorage {\n  final String key;\n  FileStorage(this.key);\n\n  Future\u003CString> read() async => window.localStorage[key] ?? '';\n  Future\u003Cvoid> write(String data) async {\n    window.localStorage[key] = data;\n  }\n}\n",[29,2741,2742,2747,2754,2764,2768,2773,2781,2785,2793,2801,2811,2815,2839,2867,2871,2875,2880,2888,2892,2900,2909,2920,2924,2951,2973,2982,2986],{"__ignoreMap":27},[32,2743,2744],{"class":34,"line":35},[32,2745,2746],{"class":38},"\u002F\u002F storage.dart (public API — conditional export)\n",[32,2748,2749,2751],{"class":34,"line":42},[32,2750,1205],{"class":228},[32,2752,2753],{"class":61}," 'storage_io.dart'\n",[32,2755,2756,2758,2760,2762],{"class":34,"line":48},[32,2757,1216],{"class":228},[32,2759,1219],{"class":235},[32,2761,1222],{"class":61},[32,2763,236],{"class":235},[32,2765,2766],{"class":34,"line":54},[32,2767,78],{"emptyLinePlaceholder":77},[32,2769,2770],{"class":34,"line":74},[32,2771,2772],{"class":38},"\u002F\u002F storage_io.dart (native — uses dart:io)\n",[32,2774,2775,2777,2779],{"class":34,"line":81},[32,2776,229],{"class":228},[32,2778,1244],{"class":61},[32,2780,236],{"class":235},[32,2782,2783],{"class":34,"line":87},[32,2784,78],{"emptyLinePlaceholder":77},[32,2786,2787,2789,2791],{"class":34,"line":93},[32,2788,1255],{"class":228},[32,2790,2631],{"class":110},[32,2792,413],{"class":235},[32,2794,2795,2797,2799],{"class":34,"line":99},[32,2796,979],{"class":228},[32,2798,1384],{"class":110},[32,2800,2642],{"class":235},[32,2802,2803,2805,2807,2809],{"class":34,"line":123},[32,2804,2647],{"class":110},[32,2806,253],{"class":235},[32,2808,1280],{"class":110},[32,2810,2654],{"class":235},[32,2812,2813],{"class":34,"line":129},[32,2814,78],{"emptyLinePlaceholder":77},[32,2816,2817,2819,2821,2823,2825,2827,2829,2831,2833,2835,2837],{"class":34,"line":135},[32,2818,1292],{"class":110},[32,2820,392],{"class":235},[32,2822,303],{"class":110},[32,2824,430],{"class":235},[32,2826,1301],{"class":57},[32,2828,1015],{"class":235},[32,2830,925],{"class":228},[32,2832,1267],{"class":110},[32,2834,2679],{"class":235},[32,2836,1311],{"class":57},[32,2838,273],{"class":235},[32,2840,2841,2843,2845,2847,2849,2851,2853,2855,2857,2859,2861,2863,2865],{"class":34,"line":141},[32,2842,1292],{"class":110},[32,2844,392],{"class":235},[32,2846,315],{"class":228},[32,2848,430],{"class":235},[32,2850,1326],{"class":57},[32,2852,253],{"class":235},[32,2854,303],{"class":110},[32,2856,1333],{"class":235},[32,2858,925],{"class":228},[32,2860,1267],{"class":110},[32,2862,2679],{"class":235},[32,2864,1340],{"class":57},[32,2866,1343],{"class":235},[32,2868,2869],{"class":34,"line":146},[32,2870,358],{"class":235},[32,2872,2873],{"class":34,"line":152},[32,2874,78],{"emptyLinePlaceholder":77},[32,2876,2877],{"class":34,"line":158},[32,2878,2879],{"class":38},"\u002F\u002F storage_web.dart (web — uses localStorage)\n",[32,2881,2882,2884,2886],{"class":34,"line":164},[32,2883,229],{"class":228},[32,2885,1363],{"class":61},[32,2887,236],{"class":235},[32,2889,2890],{"class":34,"line":181},[32,2891,78],{"emptyLinePlaceholder":77},[32,2893,2894,2896,2898],{"class":34,"line":186},[32,2895,1255],{"class":228},[32,2897,2631],{"class":110},[32,2899,413],{"class":235},[32,2901,2902,2904,2906],{"class":34,"line":192},[32,2903,979],{"class":228},[32,2905,1384],{"class":110},[32,2907,2908],{"class":235}," key;\n",[32,2910,2911,2913,2915,2917],{"class":34,"line":198},[32,2912,2647],{"class":110},[32,2914,253],{"class":235},[32,2916,1280],{"class":110},[32,2918,2919],{"class":235},".key);\n",[32,2921,2922],{"class":34,"line":204},[32,2923,78],{"emptyLinePlaceholder":77},[32,2925,2926,2928,2930,2932,2934,2936,2938,2940,2942,2945,2947,2949],{"class":34,"line":488},[32,2927,1292],{"class":110},[32,2929,392],{"class":235},[32,2931,303],{"class":110},[32,2933,430],{"class":235},[32,2935,1301],{"class":57},[32,2937,1015],{"class":235},[32,2939,1419],{"class":228},[32,2941,1422],{"class":228},[32,2943,2944],{"class":235}," window.localStorage[key] ",[32,2946,1428],{"class":228},[32,2948,1431],{"class":61},[32,2950,236],{"class":235},[32,2952,2953,2955,2957,2959,2961,2963,2965,2967,2969,2971],{"class":34,"line":493},[32,2954,1292],{"class":110},[32,2956,392],{"class":235},[32,2958,315],{"class":228},[32,2960,430],{"class":235},[32,2962,1326],{"class":57},[32,2964,253],{"class":235},[32,2966,303],{"class":110},[32,2968,1333],{"class":235},[32,2970,1419],{"class":228},[32,2972,413],{"class":235},[32,2974,2975,2978,2980],{"class":34,"line":498},[32,2976,2977],{"class":235},"    window.localStorage[key] ",[32,2979,853],{"class":228},[32,2981,1465],{"class":235},[32,2983,2984],{"class":34,"line":522},[32,2985,1470],{"class":235},[32,2987,2988],{"class":34,"line":542},[32,2989,358],{"class":235},[2600,2991,2992,2993,2996,2997,2999,3000,3002,3003,3006],{},"The conditional import ",[29,2994,2995],{},"if (dart.library.html) 'storage_web.dart'"," chooses the web implementation when ",[29,2998,1900],{}," is available, else the native (",[29,3001,2362],{},") implementation. Both export the same ",[29,3004,3005],{},"FileStorage"," class with the same API. The compiler includes only the matching file — zero runtime cost.",[2600,3008,3009,3010,3012],{},"Or, use the ",[29,3011,2358],{}," package if the \"file\" is a URL (it abstracts the platform).",[3014,3015,3016],"style",{},"html pre.shiki code .sdCPZ, html code.shiki .sdCPZ{--shiki-default:#6A737D;--shiki-github-dark:#6A737D}html pre.shiki code .sIsaT, html code.shiki .sIsaT{--shiki-default:#6F42C1;--shiki-github-dark:#B392F0}html pre.shiki code .sJ6F3, html code.shiki .sJ6F3{--shiki-default:#032F62;--shiki-github-dark:#9ECBFF}html pre.shiki code .snvgF, html code.shiki .snvgF{--shiki-default:#005CC5;--shiki-github-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html.github-dark .shiki span {color: var(--shiki-github-dark);background: var(--shiki-github-dark-bg);font-style: var(--shiki-github-dark-font-style);font-weight: var(--shiki-github-dark-font-weight);text-decoration: var(--shiki-github-dark-text-decoration);}html pre.shiki code .svdQ7, html code.shiki .svdQ7{--shiki-default:#D73A49;--shiki-github-dark:#F97583}html pre.shiki code .ssxIu, html code.shiki .ssxIu{--shiki-default:#24292E;--shiki-github-dark:#E1E4E8}",{"title":27,"searchDepth":42,"depth":42,"links":3018},[3019,3020,3024,3027,3028,3030,3031,3032],{"id":16,"depth":42,"text":17},{"id":210,"depth":42,"text":3021,"children":3022},"JS Interop — dart:js_interop & Extension Types (Dart 3.3+)",[3023],{"id":800,"depth":48,"text":801},{"id":1182,"depth":42,"text":1183,"children":3025},[3026],{"id":1496,"depth":48,"text":1497},{"id":1713,"depth":42,"text":1714},{"id":1896,"depth":42,"text":3029},"DOM Access — dart:html",{"id":2343,"depth":42,"text":2344},{"id":2450,"depth":42,"text":2451},{"id":2597,"depth":42,"text":2598},"Deep-dive into Dart's web compilation pipeline (dart2js\u002FDDC\u002FWasm), JS interop with extension types, conditional imports for platform abstraction, and web platform limitations (int precision, no isolates, no mirrors). Code-first engineering reference.","md",{},"\u002Fdart\u002F15-dart-for-the-web",{"title":5,"description":3033},"dart\u002F15-dart-for-the-web","cuvTMeWNbjjmIBVnwT9vg1rZj7pPxD_lGEDp0FlR-ZE",1789924647965]