Parcel build को obfuscate करें

@afterpack/parcel-optimizer, Parcel 2 Optimizer के रूप में हर packaged bundle को memory में obfuscate करता है, और production में 404 देने वाला chunk ship करने के बजाय build को fail closed करता है।

@afterpack/parcel-optimizer एक Parcel 2 Optimizer है, जो .parcelrc में register होता है। यह हर packaged bundle को Parcel के अपने optimize phase के दौरान memory में obfuscate करता है, इसलिए bundle कभी cleartext में disk को नहीं छूता।

@afterpack/parcel नहीं

Package का नाम @afterpack/parcel-optimizer है।

Install

$ npm install -D @afterpack/parcel-optimizer
// .parcelrc
{
  "extends": "@parcel/config-default",
  "optimizers": {
    "*.{js,mjs,cjs}": ["...", "@afterpack/parcel-optimizer"]
  }
}

"..." spread ज़रूरी है: यह Parcel के default optimizers (@parcel/optimizer-swc) को बनाए रखता है और AfterPack को आख़िर में रखता है। AfterPack minification के बाद चलता है। Peer dependency: Parcel >=2.9.0।

Build

.parcelrc entries बिना inline options वाले सादे package names होती हैं, इसलिए options आपके project root के afterpack.json से आते हैं, वह एक config फ़ाइल जिसे हर AfterPack integration पढ़ता है:

{
  "seed": "git",
  "preset": "medium"
}

केवल project-root में artifacts बनते हैं; आपके bundles के बगल में कुछ नहीं जाता:

  • हर bundle का एक protectionMap.html, .afterpack/<bundle>.<id>.protectionMap.html पर।
  • एक source map, जब sourceMap policy उसे चालू करती है। इसे सीधे लिखने के बजाय Parcel को लौटाया जाता है, इसलिए Parcel इसे अपने content hash के साथ नाम देता है और emit करता है।

.afterpack/ की अपनी .gitignore होती है; plugin आपके project की .gitignore में कभी बदलाव नहीं करता।

Verify

चूँकि कोई संयुक्त रिपोर्ट नहीं है, जिस bundle की आपको परवाह है उसे सीधे जाँचें: Parcel द्वारा package की गई हर entry या lazy chunk के लिए .afterpack/<bundle-name>.<id>.protectionMap.html। Production में maps बंद रहते हैं डिफ़ॉल्ट रूप से; override करने के लिए afterpack.json में "sourceMap": { "enabled": true } सेट करें। हर रिपोर्ट में आपका पूरा source होता है। इसे कभी commit या serve न करें।

Options

हर configuration key वहाँ सेट की जा सकती है, उदाहरण के लिए { "preset": "hard", "complexity": 40 }। protectionMap.enabled build mode के बजाय इस पर निर्भर करता है कि bundle में source map है या नहीं, और यह हमेशा gitignored .afterpack/ में जाता है। इस plugin पर कोई build.backup option नहीं है। इसे सेट करने पर warning मिलती है। स्पष्ट options हमेशा production defaults पर भारी पड़ते हैं।

Directives

Plugin directives को आपके source से पढ़ता है। कोई इस्तेमाल योग्य source map न हो, तो pass के पास recover करने को कुछ नहीं होता और वह यह बता देता है।

आपके entry module में directive recover नहीं होता। Pass DIAG_DIRECTIVE_SOURCE_UNRESOLVED रिपोर्ट करता है और module का नाम बताता है। बाकी हर non-entry module में directives source maps चालू होने पर सामान्य रूप से काम करते हैं। अगर आपको entry-module directive चाहिए, तो सुरक्षित किए जाने वाले code को किसी imported module में ले जाएँ।

Edge cases

Content-hash placeholders आपकी build को विफल कर सकते हैं

Content hashing चालू होने पर (parcel build का डिफ़ॉल्ट) और native ESM के बिना वाले target के साथ, Parcel के content-hash placeholders obfuscated strings के भीतर पहुँच जाते हैं, और हर code-split chunk production में 404 देता है।

यह plugin इस टकराव को पहचानता है और उसे ship करने के बजाय build को विफल कर देता है:

AfterPack obfuscated 1 Parcel content-hash placeholder(s) in app.[hash].js (HASH_REF_...).
  hint: Run `parcel build --no-content-hash` (chunk URLs stop being content-addressed).
  hint: Or set "complexity": 0 in afterpack.json to ship minify-only.

Parcel का default ESM output इससे अप्रभावित है।

जानने योग्य बातें

  • हर bundle के लिए एक pass, worker processes में। Parcel optimizers को प्रति bundle चलाता है, और अलग-अलग worker processes में package हुए bundles state साझा नहीं कर सकते। एक ही process में package हुए bundles एक seed साझा करते हैं। हर worker में एक ही seed pin करने के लिए, seed स्पष्ट रूप से सेट करें या AFTERPACK_seed export करें।
  • Parcel optimizer output को cache करता है। Warm .parcel-cache और बिना बदले input वाला rebuild AfterPack को दोबारा नहीं चलाता, और unpinned seed को rotate नहीं करता। नए pass के लिए .parcel-cache साफ़ करें; CI builds वैसे भी cold cache से होती हैं।
  • दो हानिरहित warnings। Parcel ES module dependencies are experimental छापता है (हर AfterPack package ESM है) और बताता है कि plugin contains non-statically analyzable dependencies (native engine का runtime binary resolution)। इनमें से कोई भी build को प्रभावित नहीं करता।

Plugin के बिना: CLI

Parcel से हमेशा की तरह build करें, फिर AfterPack को output पर चलाएँ:

$ npx parcel build
$ npx afterpack@latest dist/ --preset=medium --seed=git

Path argument न दें, तो CLI dist/ पहचान लेता है, जो Parcel का default output है; आपकी directory अलग हो तो उसका नाम दें। AfterPack directory में चलता है, हर .js/.mjs/.cjs इकट्ठा करता है और उन्हें उसी जगह obfuscate करता है। CLI run को कोई content-hash guard नहीं मिलता, और हर bundle के एक के बजाय पूरी directory के लिए एक संयुक्त protectionMap.html मिलता है। Fail-closed फिर भी लागू रहता है: मौजूद न होने वाली build dir, कोई JS फ़ाइल न होना, एक error/critical diagnostic, या ऐसी फ़ाइल जिसे engine obfuscate नहीं कर सका, सभी 1 के साथ exit करते हैं।

आगे

  • Frameworks: पूरी matrix।
  • esbuild: एक और plugin जो minification के बाद source map से directives recover करता है।
  • CLI reference: fallback रास्ते के flags पूरे विस्तार से।
  • Builds और CI: seeds, dev-बनाम-prod, वही bytes promote करना।
  • Protection Map: रिपोर्ट को पढ़ना।
  • Configuration: हर option, और कौन-सी surface उसे सेट कर सकती है।
  • Presets: पाँच पायदानों वाली सीढ़ी।