নন-জাভাস্ক্রিপ্ট রিসোর্স বান্ডলিং

জাভাস্ক্রিপ্ট থেকে কিভাবে বিভিন্ন ধরনের সম্পদ আমদানি এবং বান্ডিল করতে হয় তা জানুন।

ধরুন আপনি একটি ওয়েব অ্যাপে কাজ করছেন। সেক্ষেত্রে, সম্ভবত আপনাকে শুধুমাত্র জাভাস্ক্রিপ্ট মডিউলের সাথেই নয়, অন্যান্য সমস্ত ধরণের সম্পদের সাথেও মোকাবিলা করতে হবে—ওয়েব ওয়ার্কাররা (যা জাভাস্ক্রিপ্ট, কিন্তু নিয়মিত মডিউল গ্রাফের অংশ নয়), ছবি, স্টাইলশীট, ফন্ট, WebAssembly মডিউল এবং অন্যান্য.

এইচটিএমএল-এ সরাসরি এই সংস্থানগুলির কিছু রেফারেন্স অন্তর্ভুক্ত করা সম্ভব, তবে প্রায়শই তারা যৌক্তিকভাবে পুনর্ব্যবহারযোগ্য উপাদানগুলির সাথে সংযুক্ত থাকে। উদাহরণস্বরূপ, জাভাস্ক্রিপ্ট অংশে বাঁধা একটি কাস্টম ড্রপডাউনের জন্য একটি স্টাইলশীট, একটি টুলবার উপাদানের সাথে বাঁধা আইকন চিত্র, বা WebAssembly মডিউল এটির JavaScript আঠার সাথে বাঁধা। এই ক্ষেত্রে, তাদের JavaScript মডিউলগুলি থেকে সরাসরি সংস্থানগুলি উল্লেখ করা এবং সংশ্লিষ্ট উপাদানটি লোড করা হলে (বা যদি) গতিশীলভাবে লোড করা আরও সুবিধাজনক।

JS-এ আমদানি করা বিভিন্ন ধরনের সম্পদের গ্রাফ ভিজ্যুয়ালাইজ করা।

যাইহোক, বেশিরভাগ বড় প্রকল্পে এমন সিস্টেম তৈরি করা হয় যা অতিরিক্ত অপ্টিমাইজেশন এবং বিষয়বস্তুর পুনর্গঠন করে—উদাহরণস্বরূপ, বান্ডলিং এবং মিনিফিকেশন। তারা কোডটি কার্যকর করতে পারে না এবং প্রয়োগের ফলাফল কী হবে তা ভবিষ্যদ্বাণী করতে পারে না, বা তারা জাভাস্ক্রিপ্টের প্রতিটি সম্ভাব্য স্ট্রিং আক্ষরিক অতিক্রম করতে পারে না এবং এটি একটি রিসোর্স URL কিনা সে সম্পর্কে অনুমান করতে পারে না। তাহলে আপনি কিভাবে জাভাস্ক্রিপ্ট উপাদান দ্বারা লোড করা সেই গতিশীল সম্পদগুলিকে "দেখতে" এবং বিল্ডে অন্তর্ভুক্ত করতে পারেন?

বান্ডলারে কাস্টম আমদানি

একটি সাধারণ পদ্ধতি হল স্ট্যাটিক আমদানি সিনট্যাক্স পুনরায় ব্যবহার করা। কিছু বান্ডলারে এটি ফাইল এক্সটেনশনের মাধ্যমে স্বয়ংক্রিয়ভাবে শনাক্ত করতে পারে, অন্যরা প্লাগইনগুলিকে নিম্নলিখিত উদাহরণের মতো একটি কাস্টম URL স্কিম ব্যবহার করার অনুমতি দেয়:

// regular JavaScript import
import { loadImg } from './utils.js';

// special "URL imports" for assets
import imageUrl from 'asset-url:./image.png';
import wasmUrl from 'asset-url:./module.wasm';
import workerUrl from 'js-url:./worker.js';

loadImg(imageUrl);
WebAssembly.instantiateStreaming(fetch(wasmUrl));
new Worker(workerUrl);

যখন একটি বান্ডলার প্লাগইন একটি এক্সটেনশনের সাথে একটি আমদানি খুঁজে পায় যা এটি স্বীকৃতি দেয় বা এই জাতীয় একটি স্পষ্ট কাস্টম স্কিম ( asset-url: এবং js-url: উপরের উদাহরণে), এটি বিল্ড গ্রাফে রেফারেন্সযুক্ত সম্পদ যোগ করে, এটি চূড়ান্তভাবে অনুলিপি করে গন্তব্য, সম্পদের প্রকারের জন্য প্রযোজ্য অপ্টিমাইজেশন সঞ্চালন করে এবং রানটাইমের সময় ব্যবহার করার জন্য চূড়ান্ত URL প্রদান করে।

এই পদ্ধতির সুবিধা: জাভাস্ক্রিপ্ট ইম্পোর্ট সিনট্যাক্স পুনরায় ব্যবহার করা নিশ্চিত করে যে সমস্ত ইউআরএল স্থির এবং বর্তমান ফাইলের সাথে আপেক্ষিক, যা বিল্ড সিস্টেমের জন্য এই ধরনের নির্ভরতা সনাক্ত করা সহজ করে তোলে।

যাইহোক, এটির একটি উল্লেখযোগ্য ত্রুটি রয়েছে: এই ধরনের কোড ব্রাউজারে সরাসরি কাজ করতে পারে না, কারণ ব্রাউজার সেই কাস্টম আমদানি স্কিম বা এক্সটেনশনগুলি কীভাবে পরিচালনা করতে হয় তা জানে না। আপনি যদি সমস্ত কোড নিয়ন্ত্রণ করেন এবং যাইহোক বিকাশের জন্য একটি বান্ডলারের উপর নির্ভর করেন তবে এটি ঠিক হতে পারে, তবে ঘর্ষণ কমাতে কমপক্ষে বিকাশের সময় সরাসরি ব্রাউজারে জাভাস্ক্রিপ্ট মডিউল ব্যবহার করা ক্রমবর্ধমান সাধারণ। একটি ছোট ডেমোতে কাজ করা কেউ এমনকি উত্পাদনের ক্ষেত্রেও একটি বান্ডলারের প্রয়োজন নাও হতে পারে।

ব্রাউজার এবং বান্ডলারের জন্য ইউনিভার্সাল প্যাটার্ন

আপনি যদি একটি পুনঃব্যবহারযোগ্য কম্পোনেন্ট নিয়ে কাজ করেন, তাহলে আপনি এটিকে যেকোনো পরিবেশে কাজ করতে চান, তা ব্রাউজারে সরাসরি ব্যবহার করা হোক বা একটি বড় অ্যাপের অংশ হিসেবে পূর্ব-নির্মিত হোক। বেশিরভাগ আধুনিক বান্ডলার জাভাস্ক্রিপ্ট মডিউলগুলিতে নিম্নলিখিত প্যাটার্ন গ্রহণ করে এটির জন্য অনুমতি দেয়:

new URL('./relative-path', import.meta.url)

এই প্যাটার্নটি সরঞ্জামের মাধ্যমে স্থিরভাবে সনাক্ত করা যেতে পারে, প্রায় যেন এটি একটি বিশেষ সিনট্যাক্স, তবুও এটি একটি বৈধ জাভাস্ক্রিপ্ট অভিব্যক্তি যা সরাসরি ব্রাউজারেও কাজ করে।

এই প্যাটার্নটি ব্যবহার করার সময়, উপরের উদাহরণটি এইভাবে পুনরায় লেখা যেতে পারে:

// regular JavaScript import
import { loadImg } from './utils.js';

loadImg(new URL('./image.png', import.meta.url));
WebAssembly.instantiateStreaming(
  fetch(new URL('./module.wasm', import.meta.url)),
  { /* … */ }
);
new Worker(new URL('./worker.js', import.meta.url));

এটা কিভাবে কাজ করে? এর এটা ভেঙ্গে দেওয়া যাক. new URL(...) কনস্ট্রাক্টর একটি আপেক্ষিক ইউআরএলকে প্রথম আর্গুমেন্ট হিসেবে নেয় এবং দ্বিতীয় আর্গুমেন্ট হিসেবে দেওয়া একটি পরম ইউআরএলের বিপরীতে এটি সমাধান করে। আমাদের ক্ষেত্রে, দ্বিতীয় আর্গুমেন্টটি হল import.meta.url যা বর্তমান জাভাস্ক্রিপ্ট মডিউলের URL দেয়, তাই প্রথম আর্গুমেন্টটি এর সাপেক্ষে যেকোনো পাথ হতে পারে।

এটির গতিশীল আমদানির অনুরূপ ট্রেডঅফ রয়েছে। import(someUrl) এর মত নির্বিচারে অভিব্যক্তি সহ import(...) ব্যবহার করা সম্ভব হলেও, বান্ডলারগুলি প্রিপ্রসেস করার উপায় হিসাবে স্ট্যাটিক ইউআরএল import('./some-static-url.js') সহ একটি প্যাটার্নকে বিশেষ চিকিত্সা দেয়। কম্পাইল-টাইমে পরিচিত একটি নির্ভরতা, তবুও এটিকে তার নিজস্ব অংশে বিভক্ত করে যা গতিশীলভাবে লোড হয়।

একইভাবে, নতুন URL new URL(relativeUrl, customAbsoluteBase) এর মত নির্বিচারে অভিব্যক্তি সহ আপনি new URL(...) ব্যবহার করতে পারেন, তবুও new URL('...', import.meta.url) প্যাটার্নটি বান্ডলারদের প্রিপ্রসেস করার জন্য একটি স্পষ্ট সংকেত। এবং প্রধান জাভাস্ক্রিপ্টের পাশাপাশি একটি নির্ভরতা অন্তর্ভুক্ত করে।

অস্পষ্ট আপেক্ষিক ইউআরএল

আপনি হয়ত ভাবছেন, কেন বান্ডলাররা অন্যান্য সাধারণ প্যাটার্ন শনাক্ত করতে পারে না—উদাহরণস্বরূপ, new URL র্যাপার ছাড়া fetch('./module.wasm') ?

কারণ হল, আমদানি বিবৃতির বিপরীতে, যেকোনো গতিশীল অনুরোধ নথিতে তুলনামূলকভাবে সমাধান করা হয়, বর্তমান জাভাস্ক্রিপ্ট ফাইলে নয়। ধরা যাক আপনার নিম্নলিখিত কাঠামো আছে:

  • index.html :
    html <script src="src/main.js" type="module"></script>
  • src/
    • main.js
    • module.wasm

আপনি main.js থেকে module.wasm লোড করতে চাইলে, এটি fetch('./module.wasm') এর মতো একটি আপেক্ষিক পথ ব্যবহার করতে প্রলুব্ধ হতে পারে।

যাইহোক, fetch জাভাস্ক্রিপ্ট ফাইলের URL জানেন না যেটিতে এটি কার্যকর করা হয়েছে, পরিবর্তে, এটি নথির সাথে তুলনামূলকভাবে URLগুলি সমাধান করে৷ ফলস্বরূপ, fetch('./module.wasm') উদ্দেশ্য http://example.com/src/module.wasm এর পরিবর্তে http://example.com/module.wasm লোড করার চেষ্টা করবে এবং ব্যর্থ হবে (অথবা, আরও খারাপ, নীরবে আপনার ইচ্ছার চেয়ে আলাদা সংস্থান লোড করুন)।

আপেক্ষিক URLটিকে new URL('...', import.meta.url) এ মোড়ানোর মাধ্যমে আপনি এই সমস্যাটি এড়াতে পারেন এবং গ্যারান্টি দিতে পারেন যে যে কোনো প্রদত্ত URL বর্তমান জাভাস্ক্রিপ্ট মডিউল ( import.meta.url ) এর URL-এর সাথে সাপেক্ষে সমাধান করা হয়েছে। এটি কোনো লোডারে পাস করার আগে।

fetch('./module.wasm') fetch(new URL('./module.wasm', import.meta.url)) দিয়ে প্রতিস্থাপন করুন এবং এটি সফলভাবে প্রত্যাশিত WebAssembly মডিউলটি লোড করবে, পাশাপাশি বান্ডলারদের একটি উপায় দেবে নির্মাণের সময়ও সেই আপেক্ষিক পথগুলি খুঁজুন।

টুলিং সমর্থন

বান্ডলার

নিম্নলিখিত বান্ডলারগুলি ইতিমধ্যেই new URL স্কিম সমর্থন করে:

ওয়েব অ্যাসেম্বলি

WebAssembly এর সাথে কাজ করার সময়, আপনি সাধারণত হাত দিয়ে Wasm মডিউল লোড করবেন না, বরং টুলচেন দ্বারা নির্গত জাভাস্ক্রিপ্ট আঠালো আমদানি করবেন। নিম্নলিখিত টুলচেনগুলি আপনার জন্য হুডের নীচে বর্ণিত new URL(...) প্যাটার্ন নির্গত করতে পারে৷

Emscripten এর মাধ্যমে C/C++

Emscripten ব্যবহার করার সময়, আপনি নিম্নলিখিত বিকল্পগুলির মধ্যে একটির মাধ্যমে নিয়মিত স্ক্রিপ্টের পরিবর্তে একটি ES6 মডিউল হিসাবে জাভাস্ক্রিপ্ট আঠালো নির্গত করতে বলতে পারেন:

$ emcc input.cpp -o output.mjs
## or, if you don't want to use .mjs extension
$ emcc input.cpp -o output.js -s EXPORT_ES6

এই বিকল্পটি ব্যবহার করার সময়, আউটপুট হুডের নীচে new URL(..., import.meta.url) প্যাটার্ন ব্যবহার করবে, যাতে বান্ডলাররা স্বয়ংক্রিয়ভাবে সংশ্লিষ্ট Wasm ফাইলটি খুঁজে পেতে পারে।

আপনি একটি -pthread পতাকা যোগ করে WebAssembly থ্রেডগুলির সাথে এই বিকল্পটি ব্যবহার করতে পারেন:

$ emcc input.cpp -o output.mjs -pthread
## or, if you don't want to use .mjs extension
$ emcc input.cpp -o output.js -s EXPORT_ES6 -pthread

এই ক্ষেত্রে, জেনারেট করা ওয়েব ওয়ার্কার একই ফ্যাশনে অন্তর্ভুক্ত করা হবে এবং একইভাবে বান্ডলার এবং ব্রাউজার দ্বারাও আবিষ্কার করা যাবে।

wasm-pack / wasm-bindgen এর মাধ্যমে মরিচা

wasm-pack — WebAssembly-এর জন্য প্রাথমিক মরিচা টুলচেন—এছাড়াও বেশ কিছু আউটপুট মোড রয়েছে।

ডিফল্টরূপে, এটি একটি জাভাস্ক্রিপ্ট মডিউল নির্গত করবে যা WebAssembly ESM ইন্টিগ্রেশন প্রস্তাবের উপর নির্ভর করে। লেখার মুহুর্তে, এই প্রস্তাবটি এখনও পরীক্ষামূলক, এবং আউটপুট শুধুমাত্র Webpack এর সাথে বান্ডিল করলেই কাজ করবে।

পরিবর্তে, আপনি --target web মাধ্যমে একটি ব্রাউজার-সামঞ্জস্যপূর্ণ ES6 মডিউল নির্গত করতে wasm-pack বলতে পারেন:

$ wasm-pack build --target web

আউটপুট বর্ণিত new URL(..., import.meta.url) প্যাটার্ন ব্যবহার করবে এবং Wasm ফাইলটি বান্ডলারদের দ্বারা স্বয়ংক্রিয়ভাবে আবিষ্কৃত হবে।

আপনি যদি মরিচা দিয়ে WebAssembly থ্রেড ব্যবহার করতে চান তবে গল্পটি একটু বেশি জটিল। আরও জানতে গাইডের সংশ্লিষ্ট বিভাগটি দেখুন।

সংক্ষিপ্ত সংস্করণ হল যে আপনি নির্বিচারে থ্রেড API ব্যবহার করতে পারবেন না, তবে আপনি যদি Rayon ব্যবহার করেন, আপনি এটিকে wasm-bindgen-rayon অ্যাডাপ্টারের সাথে একত্রিত করতে পারেন যাতে এটি ওয়েবে শ্রমিকদের জন্ম দিতে পারে। wasm-bindgen-rayon দ্বারা ব্যবহৃত জাভাস্ক্রিপ্ট আঠালোতেও হুডের নিচে new URL(...) প্যাটার্ন অন্তর্ভুক্ত রয়েছে , এবং তাই শ্রমিকরা আবিষ্কারযোগ্য হবে এবং বান্ডলারদের দ্বারাও অন্তর্ভুক্ত হবে।

ভবিষ্যতের বৈশিষ্ট্য

import.meta.resolve

একটি ডেডিকেটেড import.meta.resolve(...) কল একটি সম্ভাব্য ভবিষ্যতের উন্নতি। এটি বর্তমান মডিউলের সাথে তুলনামূলকভাবে স্পেসিফায়ারগুলিকে আরও সহজবোধ্যভাবে সমাধান করার অনুমতি দেবে, অতিরিক্ত প্যারাম ছাড়াই:

new URL('...', import.meta.url)
await import.meta.resolve('...')

এটি আমদানি মানচিত্র এবং কাস্টম সমাধানকারীদের সাথে আরও ভালভাবে সংহত করবে কারণ এটি import মতো একই মডিউল রেজোলিউশন সিস্টেমের মধ্য দিয়ে যাবে৷ এটি বান্ডলারদের জন্যও একটি শক্তিশালী সংকেত হবে কারণ এটি একটি স্ট্যাটিক সিনট্যাক্স যা URL এর মতো রানটাইম API-এর উপর নির্ভর করে না।

import.meta.resolve ইতিমধ্যেই Node.js-এ একটি পরীক্ষা হিসাবে প্রয়োগ করা হয়েছে কিন্তু ওয়েবে এটি কীভাবে কাজ করবে সে সম্পর্কে এখনও কিছু অমীমাংসিত প্রশ্ন রয়েছে।

দাবী আমদানি করুন

আমদানি দাবী হল একটি নতুন বৈশিষ্ট্য যা ECMAScript মডিউল ব্যতীত অন্য প্রকারগুলি আমদানি করতে দেয়৷ আপাতত তারা JSON-এ সীমাবদ্ধ:

foo.json:

{ "answer": 42 }

main.mjs:

import json from './foo.json' assert { type: 'json' };
console.log(json.answer); // 42

এগুলি বান্ডলারদের দ্বারাও ব্যবহার করা হতে পারে এবং বর্তমানে new URL প্যাটার্ন দ্বারা আচ্ছাদিত ব্যবহারের ক্ষেত্রে প্রতিস্থাপন করা হতে পারে, তবে প্রতি-কেস ভিত্তিতে আমদানি দাবীতে প্রকারগুলি যোগ করা হয়। আপাতত তারা শুধুমাত্র JSON-কে কভার করে, CSS মডিউলগুলি শীঘ্রই আসবে, কিন্তু অন্যান্য ধরনের সম্পদের জন্য আরও সাধারণ সমাধানের প্রয়োজন হবে।

এই বৈশিষ্ট্য সম্পর্কে আরও জানতে v8.dev বৈশিষ্ট্য ব্যাখ্যাকারী দেখুন।

উপসংহার

আপনি দেখতে পাচ্ছেন, ওয়েবে নন-জাভাস্ক্রিপ্ট সংস্থানগুলি অন্তর্ভুক্ত করার বিভিন্ন উপায় রয়েছে, তবে তাদের বিভিন্ন ত্রুটি রয়েছে এবং বিভিন্ন টুলচেইন জুড়ে কাজ করে না। ভবিষ্যত প্রস্তাবগুলি আমাদেরকে বিশেষ সিনট্যাক্স সহ এই জাতীয় সম্পদ আমদানি করতে দিতে পারে, কিন্তু আমরা এখনও সেখানে নেই।

ততক্ষণ পর্যন্ত, new URL(..., import.meta.url) প্যাটার্ন হল সবচেয়ে প্রতিশ্রুতিশীল সমাধান যা ইতিমধ্যেই ব্রাউজার, বিভিন্ন বান্ডলার এবং WebAssembly টুলচেইনে কাজ করে।