ওয়েব ডেভেলপমেন্ট জগৎ বিশাল, এবং প্রতিদিন উদ্ভূত নতুন প্রযুক্তির ধ্রুবক স্রোতে হারিয়ে যাওয়া অনুভব করা সহজ। এই নতুন প্রযুক্তিগুলির বেশিরভাগই জাভাস্ক্রিপ্ট বা টাইপস্ক্রিপ্ট ব্যবহার করে নির্মিত। যাইহোক, এই নিবন্ধে, আমি আপনাকে সরাসরি আপনার ব্রাউজারের ভিতরে নেটিভ সুইফট ব্যবহার করে ওয়েব ডেভেলপমেন্টের সাথে পরিচয় করিয়ে দেব এবং আমি নিশ্চিত যে এটি আপনাকে মুগ্ধ করবে। কিভাবে এটা সম্ভব? সুইফটকে ওয়েব পেজে নেটিভভাবে কাজ করার জন্য প্রথমে WebAssembly বাইট-কোডে কম্পাইল করতে হবে এবং তারপর জাভাস্ক্রিপ্ট সেই কোডটিকে পেজে লোড করতে পারে। সংকলনের পুরো প্রক্রিয়াটি একটু জটিল কারণ আমাদের বিশেষ টুলচেইন ব্যবহার করতে হবে এবং সাহায্যকারী ফাইল তৈরি করতে হবে, সেই কারণেই এখানে সহায়ক CLI- টুল উপলব্ধ রয়েছে: কার্টন এবং ওয়েবার। তৃতীয় পক্ষের টুলচেন ব্যবহার করা কি ঠিক আছে? সম্প্রদায় মূল সুইফট টুলচেন প্যাচ করে WebAssembly-এ সুইফটকে কম্পাইল করা সম্ভব করার জন্য প্রচুর পরিমাণে কাজ করেছে। তারা প্রতিদিন আসল টুলচেন থেকে স্বয়ংক্রিয়ভাবে পরিবর্তনগুলি টেনে টুলচেন আপডেট করে এবং পরীক্ষা ব্যর্থ হলে তাদের কাঁটা ঠিক করে। তাদের লক্ষ্য হল অফিসিয়াল টুলচেইনের একটি অংশ হওয়া এবং তারা আশা করে যে এটি অদূর ভবিষ্যতে ঘটবে। SwiftWasm শক্ত কাগজ বা ওয়েবার? SwiftWasm সম্প্রদায় দ্বারা তৈরি করা হয় এবং Tokamak প্রকল্পগুলির জন্য ব্যবহার করা যেতে পারে, এটি একটি কাঠামো যা আপনাকে SwiftUI ব্যবহার করে ওয়েবসাইট লেখার ক্ষমতা দেয়। কার্টনটি SwifWeb প্রকল্পের জন্য তৈরি করা হয়। SwifWeb ভিন্ন যে এটি সমগ্র HTML এবং CSS স্ট্যান্ডার্ড, সেইসাথে সমস্ত ওয়েব API গুলিকে মোড়ানো। ওয়েবার যদিও আপনি কোড সামঞ্জস্যের জন্য SwiftUI ব্যবহার করে ওয়েব অ্যাপ লিখতে পছন্দ করতে পারেন, আমি বিশ্বাস করি এটি ভুল পদ্ধতি কারণ ওয়েব ডেভেলপমেন্ট অন্তর্নিহিতভাবে ভিন্ন এবং SwiftUI এর মতো একইভাবে যোগাযোগ করা যায় না। তাই আমি SwifWeb তৈরি করেছি, যা আপনাকে স্বয়ংক্রিয়-সম্পূর্ণতা এবং ডকুমেন্টেশন সহ সুন্দর সিনট্যাক্স ব্যবহার করে, সুইফট থেকে সরাসরি HTML, CSS এবং ওয়েব API-এর সমস্ত শক্তি ব্যবহার করার ক্ষমতা দেয়। এবং আমি ওয়েবার টুল তৈরি করেছি কারণ কার্টন সুইফওয়েব অ্যাপগুলিকে সঠিকভাবে কম্পাইল, ডিবাগ এবং স্থাপন করতে সক্ষম নয় কারণ এটি এটির জন্য তৈরি করা হয়নি। আমার নাম মিখাইল ইসাইভ, এবং আমি সুইফওয়েবের লেখক। এই নিবন্ধে, আমি আপনাকে দেখাব কিভাবে SwifWeb ব্যবহার করে একটি ওয়েবসাইট তৈরি করা শুরু করবেন। প্রয়োজনীয় সরঞ্জাম সুইফট আপনার সুইফট ইনস্টল করা দরকার, এটি পাওয়ার সবচেয়ে সহজ উপায়: macOS-এ Xcode ইনস্টল করতে হয় লিনাক্স বা উইন্ডোজে(WSL2) থেকে স্ক্রিপ্ট ব্যবহার করতে হয় swiftlang.xyz অন্যান্য ক্ষেত্রে দেখুন অফিসিয়াল ওয়েবসাইটে ইনস্টলেশন নির্দেশাবলী ওয়েবার সিএলআই আমি ওয়েবার তৈরি করেছি যাতে আপনি আপনার অ্যাপগুলি তৈরি করতে, ডিবাগ করতে এবং স্থাপন করতে সাহায্য করেন৷ MacOS-এ HomeBrew দিয়ে ইনস্টল করা সহজ (তাদের থেকে এটি ইনস্টল করুন) ওয়েবসাইট brew install swifweb/tap/webber সর্বশেষ সংস্করণে আপডেট করতে পরে চালান brew upgrade webber উবুন্টু বা উইন্ডোজে (WSL2 এ উবুন্টু) ক্লোন করুন এবং ওয়েবারকে ম্যানুয়ালি কম্পাইল করুন sudo apt-get install binaryen curl https://get.wasmer.io -sSfL | sh apt-get install npm cd /opt sudo git clone https://github.com/swifweb/webber cd webber sudo swift build -c release sudo ln -s /opt/webber/.build/release/Webber /usr/local/bin/webber শেষ সংস্করণে আপডেট করতে পরে চালান cd /opt/webber sudo git pull sudo swift build -c release শাখায় সর্বদা স্থিতিশীল কোড থাকে তাই নির্দ্বিধায় এটি থেকে আপডেটগুলি টানুন প্রধান নতুন প্রকল্প তৈরি করা হচ্ছে টার্মিনাল খুলুন এবং কার্যকর করুন webber new ইন্টারেক্টিভ মেনুতে বা বেছে নিন এবং প্রকল্পের নাম লিখুন। pwa spa নতুন তৈরি প্রকল্পে ডিরেক্টরি পরিবর্তন করুন এবং চালান। webber serve এই কমান্ডটি আপনার প্রোজেক্টকে WebAssembly-এ কম্পাইল করবে, একটি বিশেষ ফোল্ডারের মধ্যে সমস্ত প্রয়োজনীয় ফাইল প্যাকেজ করবে এবং ডিফল্টরূপে পোর্ট ব্যবহার করে সমস্ত ইন্টারফেসে আপনার প্রোজেক্ট পরিবেশন করা শুরু করবে। .webber 8888 জন্য অতিরিক্ত আর্গুমেন্ট webber serve অ্যাপের ধরন প্রগ্রেসিভ ওয়েব অ্যাপের জন্য -t pwa -একক ওয়েব অ্যাপের জন্য -t spa পরিষেবা কর্মীর লক্ষ্যের নাম (সাধারণত PWA প্রকল্পে নামে পরিচিত) Service -s Service অ্যাপ টার্গেটের নাম ( ডিফল্টরূপে ) App -a App কনসোলে আরও তথ্য প্রিন্ট করুন -v ওয়েবার সার্ভারের জন্য পোর্ট (ডিফল্ট হল ) 8888 -p 8080 বাস্তব SSL এর মত পরীক্ষা করতে ব্যবহার করুন (অনুমোদিত স্ব-স্বাক্ষরিত SSL সেটিং সহ) -p 443 স্বয়ংক্রিয়ভাবে চালু করার জন্য গন্তব্য ব্রাউজারের নাম বা --browser safari --browser chrome পরিষেবা-কর্মীদের ডিবাগ করার জন্য অনুমোদিত স্ব-স্বাক্ষরিত SSL সেটিং সহ ব্রাউজারের অতিরিক্ত উদাহরণ --browser-self-signed ছদ্মবেশী মোডে ব্রাউজারের অতিরিক্ত উদাহরণ --browser-incognito আবেদন অ্যাপটি এ শুরু হয় Sources/App/App.swift import Web @main class App: WebApp { @AppBuilder override var app: Configuration { Lifecycle.didFinishLaunching { app in app.registerServiceWorker("service") } Routes { Page { IndexPage() } Page("login") { LoginPage() } Page("article/:id") { ArticlePage() } Page("**") { NotFoundPage() } } MainStyle() } } জীবনচক্র এটি একটি iOS-এর মতো পদ্ধতিতে কাজ করে: যখন অ্যাপটি সবেমাত্র শুরু হয়েছে didFinishLaunching যখন অ্যাপটি মারা যাচ্ছে willTerminate যখন উইন্ডোটি নিষ্ক্রিয় হতে চলেছে willResignActive যখন উইন্ডো সক্রিয় থাকে didBecomeActive যখন উইন্ডোটি পটভূমিতে যাচ্ছে didEnterBackground যখন উইন্ডোটি ফোরগ্রাউন্ডে যাচ্ছে willEnterForeground এখানে সবচেয়ে দরকারী পদ্ধতি হল কারণ এটি অ্যাপটি কনফিগার করার একটি দুর্দান্ত জায়গা। আপনি এটি সত্যিই একটি iOS অ্যাপ্লিকেশন মত মনে হয় দেখুন! 😀 didFinishLaunching এখানে দরকারী সুবিধার পদ্ধতি রয়েছে: app কল করুন PWA পরিষেবা কর্মীকে নিবন্ধন করার জন্য registerServiceWorker(“serviceName“) আপেক্ষিক বা বাহ্যিক স্ক্রিপ্ট যোগ করতে কল করুন addScript(“path/to/script.js“) আপেক্ষিক বা বাহ্যিক শৈলী যোগ করতে কল করুন addStylesheet(“path/to/style.css“) আপেক্ষিক বা বাহ্যিক ফন্ট যোগ করতে কল করুন, ঐচ্ছিকভাবে সেট টাইপ addFont(“path/to/font.woff”, type:) আইকন যোগ করতে কল, ঐচ্ছিকভাবে টাইপ এবং রঙ সেট করুন addIcon(“path/to/icon“, type:color:) এছাড়াও, এটি , , ইত্যাদির মতো অতিরিক্ত লাইব্রেরি কনফিগার করার জায়গা। অটোলেআউট বুটস্ট্র্যাপ ম্যাটেরিয়ালাইজ রুট বর্তমান URL এর উপর ভিত্তি করে উপযুক্ত পৃষ্ঠা দেখানোর জন্য রাউটিং প্রয়োজন। কিভাবে রাউটিং ব্যবহার করতে হয় তা বোঝার জন্য আপনাকে বুঝতে হবে URL কি https://website.com/hello/world - এখানে হল /hello/world পথ আপনি যেমন দেখেছেন, শুরুতে, অ্যাপ ক্লাসে আমাদের সমস্ত শীর্ষ-স্তরের রুট ঘোষণা করা উচিত। টপ-লেভেল মানে এই রুটে ঘোষিত পৃষ্ঠাগুলি উইন্ডোতে পুরো জায়গাটি নিয়ে যাবে। ঠিক আছে, উদাহরণস্বরূপ রুট রুটটি তিনটি উপায়ে সেট করা যেতে পারে Page("/") { IndexPage() } Page("") { IndexPage() } Page { IndexPage() } আমার মনে হয় শেষটা সবচেয়ে সুন্দর 🙂 লগইন বা রেজিস্ট্রেশন রুট এই মত সেট করা যেতে পারে Page("login") { LoginPage() } Page("registration") { RegistrationPage() } প্যারামিটার-সম্পর্কিত রুট Page("article/:id") { ArticlePage() } উপরের উদাহরণে হল রুটের একটি গতিশীল অংশ। আমরা ক্লাসে এই আইডেন্টিফায়ারটি পুনরুদ্ধার করতে পারি এর সাথে যুক্ত নিবন্ধটি প্রদর্শন করতে। :id ArticlePage class ArticlePage: PageController { override func didLoad(with req: PageRequest) { if let articleId = req.parameters.get("id") { // Retrieve article here } } } আপনার পাথে একাধিক প্যারামিটার থাকতে পারে। একই ভাবে তাদের সব উদ্ধার করুন. প্রশ্ন পথের পরবর্তী আকর্ষণীয় জিনিসটি হল , যা ব্যবহার করাও খুব সহজ। উদাহরণ স্বরূপ, আসুন রুট বিবেচনা করা যাক, যা অনুসন্ধানের এবং ক্যোয়ারী প্যারামিটারগুলি আশা করে। ক্যোয়ারী /অনুসন্ধান text age https://website.com/search**?text=Alex&age=19** - শেষ অংশটি হল প্রশ্ন শুধু অনুসন্ধান রুট ঘোষণা Page("search") { SearchPage() } এবং এই মত ক্লাসে কোয়েরি ডেটা পুনরুদ্ধার করুন SearchPage class SearchPage: PageController { struct Query: Decodable { let text: String? let age: Int? } override func didLoad(with req: PageRequest) { do { let query = try req.query.decode(Query.self) // use optional query.text and query.age // to query search results } catch { print("Can't decode query: \(error)") } } } কিছু আপনি রুট ঘোষণা করতে ব্যবহার করতে পারেন যা এই মত নির্দিষ্ট পাথ অংশে কিছু গ্রহণ করে * Page("foo", "*", "bar") { SearchPage() } উপরের রুটটি foo এবং বারের মধ্যে যেকোনো কিছু গ্রহণ করবে, যেমন /foo/aaa/bar, /foo/bbb/bar, ইত্যাদি। ধরা-সব চিহ্নের সাহায্যে আপনি একটি বিশেষ ক্যাচ-অল রুট সেট করতে পারেন যা নির্দিষ্ট পথে অন্য রুটের সাথে মেলেনি এমন কিছু পরিচালনা করবে। ** হয় গ্লোবাল 404 রুট করতে এটি ব্যবহার করুন Page("**") { NotFoundPage() } অথবা নির্দিষ্ট পথের জন্য যেমন ব্যবহারকারী পাওয়া যায় না Page("user", "**") { UserNotFoundPage() } আসুন উপরে ঘোষিত রুটগুলির সাথে পরিস্থিতিগুলি পরিষ্কার করি৷ /user/1 - যদি /user/:id এর জন্য একটি রুট থাকে তবে এটি ফেরত দেবে। অন্যথায়, এটি পড়ে যাবে... UserPage UserNotFoundPage /user/1/hello - যদি /user/:id/hello এর জন্য রুট থাকে তবে এটি এ পড়বে UserNotFoundPage- /something - যদি /something-এর জন্য কোন রুট না থাকে তবে এটি এ পড়বে NotFoundPage- নেস্টেড রাউটিং আমরা পরবর্তী রুটের জন্য পৃষ্ঠার সম্পূর্ণ বিষয়বস্তু প্রতিস্থাপন করতে চাই না, তবে শুধুমাত্র কিছু ব্লক। এখানেই কাজে আসে! ফ্র্যাগমেন্ট রাউটার আসুন আমরা বিবেচনা করি যে পৃষ্ঠাতে আমাদের ট্যাব রয়েছে। প্রতিটি ট্যাব একটি সাবরাউট, এবং আমরা ব্যবহার করে সাবরাউটে পরিবর্তনের প্রতিক্রিয়া জানাতে চাই। /ব্যবহারকারী ফ্র্যাগমেন্ট রাউটার ক্লাসে শীর্ষ-স্তরের রুট ঘোষণা করুন অ্যাপ Page("user") { UserPage() } এবং ক্লাসে ঘোষণা করুন UserPage FragmentRouter class UserPage: PageController { @DOM override var body: DOM.Content { // NavBar is from Materialize library :) Navbar() .item("Profile") { self.changePath(to: "/user/profile") } .item("Friends") { self.changePath(to: "/user/friends") } FragmentRouter(self) .routes { Page("profile") { UserProfilePage() } Page("friends") { UserFriendsPage() } } } } উপরের উদাহরণে, এবং সাবরাউটগুলি পরিচালনা করে এবং এটি এর অধীনে রেন্ডার করে, তাই পৃষ্ঠাটি কখনই সম্পূর্ণ বিষয়বস্তু পুনরায় লোড করে না কিন্তু শুধুমাত্র নির্দিষ্ট অংশগুলিকে। ফ্র্যাগমেন্টরাউটার /user/profile /user/friends Navbar একই বা ভিন্ন সাবরুট সহ একাধিক খণ্ডও ঘোষণা করা যেতে পারে এবং তারা সবগুলি জাদুর মতো একসাথে কাজ করবে! Btw হল একটি এবং আপনি কল করে এটি কনফিগার করতে পারেন FragmentRouter Div FragmentRouter(self) .configure { div in // do anything you want with the div } স্টাইলশীট আপনি ঐতিহ্যগত CSS ফাইল ব্যবহার করতে পারেন, কিন্তু আপনার কাছে সুইফটে লেখা একটি স্টাইলশীট ব্যবহার করার নতুন, জাদুকরী ক্ষমতাও রয়েছে! বেসিক সুইফট ব্যবহার করে একটি CSS নিয়ম ঘোষণা করতে আমাদের কাছে রয়েছে অবজেক্ট। রুল এটি তার পদ্ধতি কল করে ঘোষণামূলকভাবে নির্মিত হতে পারে Rule(...selector...) .alignContent(.baseline) .color(.red) // or rgba/hex color .margin(v: 0, h: .auto) অথবা @resultBuilder ব্যবহার করে SwiftUI-এর মতো উপায় Rule(...selector...) { AlignContent(.baseline) Color(.red) Margin(v: 0, h: .auto) } উভয় পথই সমান, যাইহোক, আমি টাইপ করার ঠিক পরে স্বয়ংসম্পূর্ণতার কারণে প্রথমটিকে পছন্দ করি 😀 . MDN-এ বর্ণিত সমস্ত CSS পদ্ধতি উপলব্ধ। তার চেয়ে বেশি এটি স্বয়ংক্রিয়ভাবে ব্রাউজার উপসর্গ পরিচালনা করে! যাইহোক, আপনি কিছু নির্দিষ্ট ক্ষেত্রে এইভাবে কাস্টম সম্পত্তি সেট করতে পারেন Rule(...selector...) .custom("customKey", "customValue") নির্বাচক কোন উপাদানের নিয়মকে প্রভাবিত করতে হবে তা নির্ধারণ করতে আমাদের একটি নির্বাচক সেট করতে হবে। আমি ডাটাবেসের ক্যোয়ারী হিসাবে নির্বাচককে দেখি, কিন্তু সেই নির্বাচক ক্যোয়ারীটির অংশগুলিকে আমি পয়েন্টার বলি। একটি পয়েন্টার তৈরি করার সবচেয়ে সহজ উপায় হল কাঁচা স্ট্রিং ব্যবহার করে শুরু করা Pointer("a") কিন্তু সঠিক দ্রুত উপায় হল এই মত প্রয়োজনীয় HTML ট্যাগে কল করে এটি তৈরি করা .pointer H1.pointer // h1 A.pointer // a Pointer.any // * Class("myClass").pointer // .myClass Id("myId").pointer // #myId এটি বেসিক পয়েন্টার সম্পর্কে, তবে তাদেরও মডিফায়ার রয়েছে যেমন ইত্যাদি। :hover :first :first-child H1.pointer.first // h1:first H1.pointer.firstChild // h1:first-child H1.pointer.hover // h1:hover আপনি যেকোন বিদ্যমান সংশোধক ঘোষণা করতে পারেন, তারা সব উপলব্ধ। যদি কিছু অনুপস্থিত থাকে তবে এটি যোগ করার জন্য একটি এক্সটেনশন করতে দ্বিধা করবেন না! এবং প্রত্যেকের জন্য এটি যোগ করতে গিথুবে পুল অনুরোধ পাঠাতে ভুলবেন না। আপনি পয়েন্টার সংযুক্ত করতে পারেন H1.class(.myClass) // h1.myClass H1.id(.myId) // h1#myId H1.id(.myId).disabled // h1#myId:disabled Div.pointer.inside(P.pointer) // div p Div.pointer.parent(P.pointer) // div > p Div.pointer.immediatedlyAfter(P.pointer) // Div + p P.pointer.precededBy(Ul.pointer) // p ~ ul নির্বাচক কীভাবে ব্যবহার করবেন নিয়মে Rule(Pointer("a")) // or Rule(A.pointer) কিভাবে একাধিক নির্বাচক ব্যবহার করবেন নিয়মে Rule(A.pointer, H1.id(.myId), Div.pointer.parent(P.pointer)) এটি নিম্নলিখিত CSS কোড তৈরি করে a, h1#myId, div > p { } প্রতিক্রিয়াশীলতা আসুন আমাদের অ্যাপের জন্য অন্ধকার এবং হালকা শৈলী ঘোষণা করি এবং পরে, আমরা সহজেই তাদের মধ্যে পরিবর্তন করতে সক্ষম হব। import Web @main class App: WebApp { enum Theme { case light, dark } @State var theme: Theme = .light @AppBuilder override var app: Configuration { // ... Lifecycle, Routes ... LightStyle().disabled($theme.map { $0 != .happy }) DarkStyle().disabled($theme.map { $0 != .sad }) } } এবং আলাদা ফাইলে বা যেমন App.swift-এ ঘোষণা করা যেতে পারে LightStyle DarkStyle class LightStyle: Stylesheet { @Rules override var rules: Rules.Content { Rule(Body.pointer).backgroundColor(.white) Rule(H1.pointer).color(.black) } } class DarkStyle: Stylesheet { @Rules override var rules: Rules.Content { Rule(Body.pointer).backgroundColor(.black) Rule(H1.pointer).color(.white) } } এবং তারপর কোথাও কিছু পৃষ্ঠার UI শুধু কল App.current.theme = .light // to switch to light theme // or App.current.theme = .dark // to switch to dark theme এবং এটি সম্পর্কিত স্টাইলশীটগুলি সক্রিয় বা নিষ্ক্রিয় করবে! এটা শান্ত না? 😎 কিন্তু আপনি বলতে পারেন যে সিএসএসের পরিবর্তে সুইফটে শৈলী বর্ণনা করা কঠিন, তাহলে কি লাভ? মূল কথা হলো প্রতিক্রিয়াশীলতা! আমরা CSS বৈশিষ্ট্য সহ @State ব্যবহার করতে পারি এবং ফ্লাইতে মান পরিবর্তন করতে পারি! একবার দেখুন, আমরা কিছু প্রতিক্রিয়াশীল সম্পত্তি সহ একটি ক্লাস তৈরি করতে পারি এবং রানটাইমে যেকোন সময় এটি পরিবর্তন করতে পারি, তাই স্ক্রিনের যে কোনও উপাদান যা সেই ক্লাসটি ব্যবহার করে আপডেট করা হবে! এটি অনেক উপাদানের জন্য ক্লাস স্যুইচ করার চেয়ে অনেক বেশি কার্যকর! import Web @main class App: WebApp { @State var reactiveColor = Color.cyan @AppBuilder override var app: Configuration { // ... Lifecycle, Routes ... MainStyle() } } extension Class { static var somethingCool: Class { "somethingCool" } } class MainStyle: Stylesheet { @Rules override var rules: Rules.Content { // for all elements with `somethingCool` class Rule(Class.hello.pointer) .color(App.current.$reactiveColor) // for H1 and H2 elements with `somethingCool` class Rule(H1.class(.hello), H2.class(.hello)) .color(App.current.$reactiveColor) } } পরে কোডের যেকোনো জায়গা থেকে শুধু কল করুন App.current.reactiveColor = .yellow // or any color you want এবং এটি স্টাইলশীটে এবং এটি ব্যবহার করে এমন সমস্ত উপাদানগুলিতে রঙ আপডেট করবে 😜 এছাড়াও, একটি স্টাইলশীটে কাঁচা CSS যোগ করা সম্ভব class MainStyle: Stylesheet { @Rules override var rules: Rules.Content { // for all elements with `somethingCool` class Rule(Class.hello.pointer) .color(App.current.$reactiveColor) // for H1 and H2 elements with `somethingCool` class Rule(H1.class(.hello), H2.class(.hello)) .color(App.current.$reactiveColor) """ /* Raw CSS goes here */ body { margin: 0; padding: 0; } """ } } আপনি যতবার প্রয়োজন ততবার কাঁচা CSS স্ট্রিংগুলি মিশ্রিত করতে পারেন পাতা রাউটার প্রতিটি রুটে পেজ রেন্ডার করছে। পৃষ্ঠা হল থেকে উত্তরাধিকারসূত্রে প্রাপ্ত যেকোন শ্রেণী। PageController লাইফসাইকেল পদ্ধতি রয়েছে যেমন , UI মেথড এবং , এবং HTML উপাদানের জন্য প্রপার্টি র্যাপার ভেরিয়েবল। পেজ কন্ট্রোলারের willLoad didLoad willUnload didUnload buildUI body টেকনিক্যালি মাত্র একটি ডিভ এবং আপনি পদ্ধতিতে এর যে কোনো বৈশিষ্ট্য সেট করতে পারেন। পেজকন্ট্রোলার buildUI class IndexPage: PageController { // MARK: - Lifecycle override func willLoad(with req: PageRequest) { super.willLoad(with: req) } override func didLoad(with req: PageRequest) { super.didLoad(with: req) // set page title and metaDescription self.title = "My Index Page" self.metaDescription = "..." // also parse query and hash here } override func willUnload() { super.willUnload() } override func didUnload() { super.didUnload() } // MARK: - UI override func buildUI() { super.buildUI() // access any properties of the page's div here // eg self.backgroundcolor(.lightGrey) // optionally call body method here to add child HTML elements body { P("Hello world") } // or alternatively self.appendChild(P("Hello world")) } // the best place to declare any child HTML elements @DOM override var body: DOM.Content { H1("Hello world") P("Text under title") Button("Click me") { self.alert("Click!") print("button clicked") } } } যদি আপনার পৃষ্ঠাটি ছোট হয় তবে আপনি এই সংক্ষিপ্ত উপায়ে এটি ঘোষণা করতে পারেন PageController { page in H1("Hello world") P("Text under title") Button("Click me") { page.alert("Click!") print("button clicked") } } .backgroundcolor(.lightGrey) .onWillLoad { page in } .onDidLoad { page in } .onWillUnload { page in } .onDidUnload { page in } এটা সুন্দর এবং laconic না? 🥲 বোনাস সুবিধার পদ্ধতি - সরাসরি জেএস পদ্ধতি alert(message: String) alert - ইউআরএল পাথ পরিবর্তন করা changePath(to: String) এইচটিএমএল উপাদান অবশেষে, আমি আপনাকে বলব কিভাবে(!) এইচটিএমএল এলিমেন্ট তৈরি এবং ব্যবহার করতে হয়! সমস্ত HTML উপাদান তাদের বৈশিষ্ট্য সহ সুইফটে উপলব্ধ, সম্পূর্ণ তালিকা যেমন এ। MDN- HTML উপাদানগুলির একটি উদাহরণ সংক্ষিপ্ত তালিকা: সুইফওয়েব কোড HTML কোড Div() <div></div> H1(“text“) <h1>text</h1> A(“Click me“).href(““).target(.blank) <a href=”” target=”_blank”>Click me</a> Button(“Click“).onClick { print(“click“) } <button onclick=”…”>Click</button> InputText($text).placeholder("Title") <input type=”text” placeholder=”title”> InputCheckbox($checked) <input type=”checkbox”> আপনি দেখতে পাচ্ছেন, সুইফটে যেকোনো এইচটিএমএল ট্যাগ অ্যাক্সেস করা খুবই সহজ কারণ ইনপুট ব্যতীত সেগুলি একই নামে উপস্থাপন করা হয়। এটি কারণ বিভিন্ন ইনপুট প্রকারের বিভিন্ন পদ্ধতি রয়েছে এবং আমি সেগুলি মিশ্রিত করতে চাইনি। সরল Div Div() আমরা এর মতো এর সমস্ত বৈশিষ্ট্য এবং শৈলী বৈশিষ্ট্যগুলি অ্যাক্সেস করতে পারি Div().class(.myDivs) // <div class="myDivs"> .id(.myDiv) // <div id="myDiv"> .backgroundColor(.green) // <div style="background-color: green;"> .onClick { // adds `onClick` listener directly to the DOM element print("Clicked on div") } .attribute("key", "value") // <div key="value"> .attribute("boolKey", true, .trueFalse) // <div boolKey="true"> .attribute("boolKey", true, .yesNo) // <div boolKey="yes"> .attribute("checked", true, .keyAsValue) // <div checked="checked"> .attribute("muted", true, .keyWithoutValue) // <div muted> .custom("border", "2px solid red") // <div style="border: 2px solid red;"> সাবক্লাসিং সাবক্লাস এইচটিএমএল উপাদান এটির জন্য পূর্বনির্ধারিত শৈলী নির্ধারণ করতে, অথবা অনেকগুলি পূর্বনির্ধারিত চাইল্ড উপাদান এবং বাইরে উপলব্ধ কিছু সুবিধাজনক পদ্ধতি সহ একটি যৌগিক উপাদান তৈরি করতে, বা এবং এর মতো জীবনচক্র ইভেন্টগুলি অর্জন করতে। didAddToDOM didRemoveFromDOM চলুন একটি এলিমেন্ট তৈরি করি যা শুধুমাত্র একটি কিন্তু পূর্বনির্ধারিত ক্লাস সহ Divider Div .divider public class Divider: Div { // it is very important to override the name // because otherwise it will be <divider> in HTML open class override var name: String { "\(Div.self)".lowercased() } required public init() { super.init() } // this method executes immediately after any init method public override func postInit() { super.postInit() // here we are adding `divider` class self.class(.divider) } } সাবক্লাস করার সময় সুপার মেথড কল করা খুবই গুরুত্বপূর্ণ। এটি ছাড়া আপনি অপ্রত্যাশিত আচরণ অনুভব করতে পারেন। DOM এ সংযুক্ত করা হচ্ছে এলিমেন্টটি এখনই বা পরে বা DOM-এ যুক্ত করা যেতে পারে। PageController HTML উপাদানের এখুনি Div { H1("Title") P("Subtitle") Div { Ul { Li("One") Li("Two") } } } অথবা পরে ব্যবহার করে lazy var lazy var myDiv1 = Div() lazy var myDiv2 = Div() Div { myDiv1 myDiv2 } তাই আপনি আগে থেকে একটি ঘোষণা করতে পারেন এবং পরে যেকোনো সময় এটি DOM-এ যোগ করতে পারেন! HTML উপাদান DOM থেকে সরানো হচ্ছে lazy var myDiv = Div() Div { myDiv } // somewhere later myDiv.remove() অভিভাবক উপাদান অ্যাক্সেস করুন যেকোনো HTML উপাদানের একটি ঐচ্ছিক সুপারভিউ প্রপার্টি থাকে যা DOM-এ যোগ করা হলে তার অভিভাবককে অ্যাক্সেস দেয় Div().superview?.backgroundColor(.red) যদি/অন্য শর্ত আমাদের প্রায়শই শুধুমাত্র নির্দিষ্ট পরিস্থিতিতে উপাদানগুলি দেখাতে হয় তাই এর জন্য ব্যবহার করি if/else lazy var myDiv1 = Div() lazy var myDiv2 = Div() lazy var myDiv3 = Div() var myDiv4: Div? var showDiv2 = true Div { myDiv1 if showDiv2 { myDiv2 } else { myDiv3 } if let myDiv4 = myDiv4 { myDiv4 } else { P("Div 4 was nil") } } কিন্তু এটি প্রতিক্রিয়াশীল নয়। আপনি সেট করার চেষ্টা করলে কিছুই হবে না। showDiv2 false প্রতিক্রিয়াশীল উদাহরণ lazy var myDiv1 = Div() lazy var myDiv2 = Div() lazy var myDiv3 = Div() @State var showDiv2 = true Div { myDiv1 myDiv2.hidden($showDiv2.map { !$0 }) // shows myDiv2 if showDiv2 == true myDiv3.hidden($showDiv2.map { $0 }) // shows myDiv3 if showDiv2 == false } কেন আমরা $showDiv2.map {…} ব্যবহার করব ? সাজানো: কারণ এটি SwiftUI নয়। আদৌ। । নীচে @State সম্পর্কে আরও পড়ুন কাঁচা HTML আপনাকে পেজ বা এইচটিএমএল এলিমেন্টে কাঁচা এইচটিএমএল যোগ করতে হতে পারে এবং এটি সহজেই সম্ভব Div { """ <a href="https://google.com">Go to Google</a> """ } প্রতিটির জন্য স্ট্যাটিক উদাহরণ let names = ["Bob", "John", "Annie"] Div { ForEach(names) { name in Div(name) } // or ForEach(names) { index, name in Div("\(index). \(name)") } // or with range ForEach(1...20) { index in Div() } // and even like this 20.times { Div().class(.shootingStar) } } গতিশীল উদাহরণ @State var names = ["Bob", "John", "Annie"] Div { ForEach($names) { name in Div(name) } // or with index ForEach($names) { index, name in Div("\(index). \(name)") } } Button("Change 1").onClick { // this will append new Div with name automatically self.names.append("George") } Button("Change 2").onClick { // this will replace and update Divs with names automatically self.names = ["Bob", "Peppa", "George"] } সিএসএস উপরের উদাহরণগুলির মতোই, তবে উপলব্ধ BuilderFunction Stylesheet { ForEach(1...20) { index in CSSRule(Div.pointer.nthChild("\(index)")) // set rule properties depending on index } 20.times { index in CSSRule(Div.pointer.nthChild("\(index)")) // set rule properties depending on index } } আপনি লুপগুলিতে ব্যবহার করতে পারেন শুধুমাত্র নিম্নলিখিত উদাহরণে একটি মানের মত কিছু মান একবার গণনা করতে ForEach BuilderFunction delay ForEach(1...20) { index in BuilderFunction(9999.asRandomMax()) { delay in CSSRule(Pointer(".shooting_star").nthChild("\(index)")) .custom("top", "calc(50% - (\(400.asRandomMax() - 200)px))") .custom("left", "calc(50% - (\(300.asRandomMax() + 300)px))") .animationDelay(delay.ms) CSSRule(Pointer(".shooting_star").nthChild("\(index)").before) .animationDelay(delay.ms) CSSRule(Pointer(".shooting_star").nthChild("\(index)").after) .animationDelay(delay.ms) } } এটি একটি যুক্তি হিসাবে ফাংশন নিতে পারে BuilderFunction(calculate) { calculatedValue in // CSS rule or DOM element } func calculate() -> Int { return 1 + 1 } এইচটিএমএল উপাদানগুলির জন্যও উপলব্ধ :) বিল্ডার ফাংশন @State-এর সাথে প্রতিক্রিয়া আজকাল ঘোষণামূলক জন্য সবচেয়ে আকাঙ্ক্ষিত জিনিস। @State প্রোগ্রামিংয়ের যেমনটি আমি আপনাকে উপরে বলেছি: এটি SwiftUI নয়, তাই এমন কোনও বিশ্বব্যাপী রাষ্ট্রীয় মেশিন নেই যা সবকিছু ট্র্যাক করে এবং পুনরায় আঁকে। এবং এইচটিএমএল উপাদানগুলি অস্থায়ী স্ট্রাকট নয় কিন্তু ক্লাস, তাই তারা বাস্তব বস্তু এবং আপনি তাদের সরাসরি অ্যাক্সেস আছে. এটা অনেক ভালো এবং নমনীয়, আপনার সব নিয়ন্ত্রণ আছে। ফণা অধীনে এটা কি? এটি একটি সম্পত্তি মোড়ক যা সমস্ত গ্রাহককে এর পরিবর্তন সম্পর্কে অবহিত করে। পরিবর্তন সাবস্ক্রাইব কিভাবে? enum Countries { case usa, australia, mexico } @State var selectedCounty: Countries = .usa $selectedCounty.listen { print("country changed") } $selectedCounty.listen { newValue in print("country changed to \(newValue)") } $selectedCounty.listen { oldValue, newValue in print("country changed from \(oldValue) to \(newValue)") } কিভাবে HTML উপাদান পরিবর্তনের প্রতিক্রিয়া করতে পারে? সহজ পাঠ্য উদাহরণ @State var text = "Hello world!" H1($text) // whenever text changes it updates inner-text in H1 InputText($text) // while user is typing text it updates $text which updates H1 সহজ সংখ্যা উদাহরণ @State var height = 20.px Div().height($height) // whenever height var changes it updates height of the Div সহজ বুলিয়ান উদাহরণ @State var hidden = false Div().hidden($hidden) // whenever hidden changes it updates visibility of the Div ম্যাপিং উদাহরণ @State var isItCold = true H1($isItCold.map { $0 ? "It is cold 🥶" : "It is not cold 😌" }) দুটি রাজ্যের ম্যাপিং @State var one = true @State var two = true Div().display($one.and($two).map { one, two in // returns .block if both one and two are true one && two ? .block : .none }) দুইটির বেশি রাজ্যের ম্যাপিং @State var one = true @State var two = true @State var three = 15 Div().display($one.and($two).map { one, two in // returns true if both one and two are true one && two }.and($three).map { oneTwo, three in // here oneTwo is a result of the previous mapping // returns .block if oneTwo is true and three is 15 oneTwo && three == 15 ? .block : .none }) সমস্ত HTML এবং CSS বৈশিষ্ট্য মানগুলি পরিচালনা করতে পারে @State এক্সটেনশন HTML উপাদানগুলি প্রসারিত করুন আপনি Div মত কংক্রিট উপাদান কিছু সুবিধাজনক পদ্ধতি যোগ করতে পারেন extension Div { func makeItBeautiful() {} } অথবা উপাদানের গোষ্ঠী যদি আপনি তাদের পিতামাতার জানেন। class কয়েকটি অভিভাবক ক্লাস আছে। - এমন উপাদানগুলির জন্য যা স্ট্রিং দিয়ে শুরু করা যেতে পারে, যেমন , , ইত্যাদি। BaseActiveStringElement a h1 - সমস্ত উপাদানের জন্য যা এর ভিতরে বিষয়বস্তু থাকতে পারে, যেমন , , ইত্যাদি। BaseContentElement div ul - সমস্ত উপাদানের জন্য BaseElement তাই সব উপাদানের জন্য এক্সটেনশন এভাবে লেখা যেতে পারে extension BaseElement { func doSomething() {} } রং ঘোষণা করুন শ্রেণী রঙের জন্য দায়ী। এটিতে পূর্বনির্ধারিত HTML-রঙ রয়েছে, তবে আপনার নিজস্ব থাকতে পারে রঙের extension Color { var myColor1: Color { .hex(0xf1f1f1) } // which is 0xF1F1F1 var myColor2: Color { .hsl(60, 60, 60) } // which is hsl(60, 60, 60) var myColor3: Color { .hsla(60, 60, 60, 0.8) } // which is hsla(60, 60, 60, 0.8) var myColor4: Color { .rgb(60, 60, 60) } // which is rgb(60, 60, 60) var myColor5: Color { .rgba(60, 60, 60, 0.8) } // which is rgba(60, 60, 60, 0.8) } তারপর এটি এর মত ব্যবহার করুন H1(“Text“).color(.myColor1) ক্লাস ঘোষণা করুন extension Class { var my: Class { "my" } } তারপর এর মত ব্যবহার করুন Div().class(.my) আইডি ঘোষণা করুন extension Id { var myId: Id { "my" } } তারপর এর মত ব্যবহার করুন Div().id(.my) ওয়েব API জানলা অবজেক্ট সম্পূর্ণরূপে মোড়ানো এবং ভেরিয়েবলের মাধ্যমে অ্যাক্সেসযোগ্য। window App.current.window সম্পূর্ণ রেফারেন্স এ উপলব্ধ। MDN নিচে সংক্ষিপ্ত ওভারভিউ করা যাক ফোরগ্রাউন্ড পতাকা আপনি এ বা সরাসরি এইভাবে এটি শুনতে পারেন App.swift Lifecycle App.current.window.$isInForeground.listen { isInForeground in // foreground flag changed } অথবা যে কোন সময় যে কোন জায়গায় এটি পড়ুন if App.current.window.isInForeground { // do somethign } অথবা এইচটিএমএল উপাদানের সাথে এটিতে প্রতিক্রিয়া দেখান Div().backgroundColor(App.current.window.$isInForeground.map { $0 ? .grey : .white }) সক্রিয় পতাকা এটি ফোরগ্রাউন্ড পতাকার মতই, কিন্তু এর মাধ্যমে অ্যাক্সেসযোগ্য App.current.window.isActive এটি সনাক্ত করে যে কোনও ব্যবহারকারী এখনও উইন্ডোর ভিতরে ইন্টারঅ্যাক্ট করছে কিনা। অনলাইন স্ট্যাটাস ফোরগ্রাউন্ড পতাকার মতই, কিন্তু মাধ্যমে অ্যাক্সেসযোগ্য App.current.window.isOnline এটি সনাক্ত করে যে কোনও ব্যবহারকারীর এখনও ইন্টারনেট অ্যাক্সেস আছে কিনা। ডার্কমোড স্ট্যাটাস ফোরগ্রাউন্ড পতাকার মতই, কিন্তু এর মাধ্যমে অ্যাক্সেসযোগ্য App.current.window.isDark এটি সনাক্ত করে যে ব্যবহারকারীর ব্রাউজার বা অপারেটিং সিস্টেম ডার্ক মোডে আছে কিনা। অভ্যন্তরীণ আকার স্ক্রলবার সহ উইন্ডোর বিষয়বস্তু এলাকার (ভিউপোর্ট) আকার হল অবজেক্টের ভিতরে এবং মান। App.current.window.innerSize সাইজ width height ভেরিয়েবল হিসাবেও উপলব্ধ। @State বাইরের আকার টুলবার/স্ক্রলবার সহ ব্রাউজার উইন্ডোর আকার। হল অবজেক্টের ভিতরে এবং মান। App.current.window.outerSize সাইজ width height ভেরিয়েবল হিসাবেও উপলব্ধ। @State পর্দা স্ক্রিনের বৈশিষ্ট্যগুলি পরিদর্শনের জন্য বিশেষ বস্তু যেখানে বর্তমান উইন্ডোটি রেন্ডার করা হচ্ছে। এর মাধ্যমে উপলব্ধ। App.current.window.screen সবচেয়ে আকর্ষণীয় সম্পত্তি সাধারণত হয়। pixelRatio ইতিহাস ব্যবহারকারীর দ্বারা পরিদর্শন করা URL গুলি রয়েছে (একটি ব্রাউজার উইন্ডোর মধ্যে)। বা শুধু এর মাধ্যমে উপলব্ধ। App.current.window.history History.shared এটি ভেরিয়েবল হিসাবে অ্যাক্সেসযোগ্য, তাই প্রয়োজনে আপনি এর পরিবর্তনগুলি শুনতে পারেন। @State App.current.window.$history.listen { history in // read history properties } এটি সহজ পরিবর্তনশীল হিসাবে অ্যাক্সেসযোগ্য History.shared.length // size of the history stack History.shared.back() // to go back in history stack History.shared.forward() // to go forward in history stack History.shared.go(offset:) // going to specific index in history stack আরও বিশদ এ উপলব্ধ। MDN অবস্থান বর্তমান URL সম্পর্কে তথ্য রয়েছে। বা শুধু মাধ্যমে উপলব্ধ। App.current.window.location Location.shared এটি ভেরিয়েবল হিসাবে অ্যাক্সেসযোগ্য, তাই প্রয়োজনে আপনি এর পরিবর্তনগুলি শুনতে পারেন। @State যেমন রাউটার কাজ করে এইভাবে। App.current.window.$location.listen { location in // read location properties } এটি একটি সাধারণ পরিবর্তনশীল হিসাবে অ্যাক্সেসযোগ্য Location.shared.href // also $href Location.shared.host // also $host Location.shared.port // also $port Location.shared.pathname // also $pathname Location.shared.search // also $search Location.shared.hash // also $hash আরও বিশদ এ উপলব্ধ। MDN নেভিগেটর ব্রাউজার সম্পর্কে তথ্য রয়েছে। বা শুধু এর মাধ্যমে উপলব্ধ App.current.window.navigator Navigator.shared সবচেয়ে আকর্ষণীয় বৈশিষ্ট্য সাধারণত । userAgent platform language cookieEnabled স্থানীয় স্টোরেজ একটি ওয়েব ব্রাউজারে কী/মান জোড়া সংরক্ষণ করার অনুমতি দেয়। মেয়াদ শেষ হওয়ার তারিখ ছাড়াই ডেটা সঞ্চয় করে। বা শুধু হিসাবে উপলব্ধ। App.current.window.localStorage LocalStorage.shared // You can save any value that can be represented in JavaScript LocalStorage.shared.set("key", "value") // saves String LocalStorage.shared.set("key", 123) // saves Int LocalStorage.shared.set("key", 0.8) // saves Double LocalStorage.shared.set("key", ["key":"value"]) // saves Dictionary LocalStorage.shared.set("key", ["v1", "v2"]) // saves Array // Getting values back LocalStorage.shared.string(forKey: "key") // returns String? LocalStorage.shared.integer(forKey: "key") // returns Int? LocalStorage.shared.string(forKey: "key") // returns String? LocalStorage.shared.value(forKey: "key") // returns JSValue? // Removing item LocalStorage.shared.removeItem(forKey: "key") // Removing all items LocalStorage.shared.clear() ট্র্যাকিং পরিবর্তন LocalStorage.onChange { key, oldValue, newValue in print("LocalStorage: key \(key) has been updated") } সমস্ত আইটেম অপসারণ ট্র্যাকিং LocalStorage.onClear { print("LocalStorage: all items has been removed") } সেশন স্টোরেজ একটি ওয়েব ব্রাউজারে কী/মান জোড়া সংরক্ষণ করার অনুমতি দেয়। শুধুমাত্র একটি সেশনের জন্য ডেটা সঞ্চয় করে। বা শুধু হিসাবে উপলব্ধ। App.current.window.sessionStorage SessionStorage.shared API উপরে বর্ণিত মতোই। লোকালস্টোরেজের দলিল ব্রাউজারে লোড হওয়া যেকোন ওয়েব পৃষ্ঠার প্রতিনিধিত্ব করে এবং ওয়েব পৃষ্ঠার বিষয়বস্তুতে একটি এন্ট্রি পয়েন্ট হিসাবে কাজ করে৷ এর মাধ্যমে উপলব্ধ। App.current.window.document App.current.window.document.title // also $title App.current.window.document.metaDescription // also $metaDescription App.current.window.document.head // <head> element App.current.window.document.body // <body> element App.current.window.documentquerySelector("#my") // returns BaseElement? App.current.window.document.querySelectorAll(".my") // returns [BaseElement] স্থানীয়করণ স্ট্যাটিক স্থানীয়করণ ক্লাসিক স্থানীয়করণ স্বয়ংক্রিয় এবং ব্যবহারকারী সিস্টেম ভাষার উপর নির্ভর করে কিভাবে ব্যবহার করে H1(String( .en("Hello"), .fr("Bonjour"), .ru("Привет"), .es("Hola"), .zh_Hans("你好"), .ja("こんにちは"))) গতিশীল স্থানীয়করণ আপনি যদি স্ক্রিনে অন-দ্য-ফ্লাই স্থানীয় স্ট্রিংগুলি পরিবর্তন করতে চান (পৃষ্ঠা পুনরায় লোড না করে) আপনি কল করে বর্তমান ভাষা পরিবর্তন করতে পারেন Localization.current = .es আপনি যদি ব্যবহারকারীর ভাষাটি কুকিজ বা স্থানীয় স্টোরেজে কোথাও সংরক্ষণ করেন তবে আপনাকে এটি অ্যাপ লঞ্চে সেট করতে হবে Lifecycle.didFinishLaunching { Localization.current = .es } কিভাবে ব্যবহার করে H1(LString( .en("Hello"), .fr("Bonjour"), .ru("Привет"), .es("Hola"), .zh_Hans("你好"), .ja("こんにちは"))) উন্নত উদাহরণ H1(Localization.currentState.map { "Curent language: \($0.rawValue)" }) H2(LString(.en("English string"), .es("Hilo Español"))) Button("change lang").onClick { Localization.current = Localization.current.rawValue.contains("en") ? .es : .en } আনুন import FetchAPI Fetch("https://jsonplaceholder.typicode.com/todos/1") { switch $0 { case .failure: break case .success(let response): print("response.code: \(response.status)") print("response.statusText: \(response.statusText)") print("response.ok: \(response.ok)") print("response.redirected: \(response.redirected)") print("response.headers: \(response.headers.dictionary)") struct Todo: Decodable { let id, userId: Int let title: String let completed: Bool } response.json(as: Todo.self) { switch $0 { case .failure(let error): break case .success(let todo): print("decoded todo: \(todo)") } } } } XMLHttp অনুরোধ import XMLHttpRequest XMLHttpRequest() .open(method: "GET", url: "https://jsonplaceholder.typicode.com/todos/1") .onAbort { print("XHR onAbort") }.onLoad { print("XHR onLoad") }.onError { print("XHR onError") }.onTimeout { print("XHR onTimeout") }.onProgress{ progress in print("XHR onProgress") }.onLoadEnd { print("XHR onLoadEnd") }.onLoadStart { print("XHR onLoadStart") }.onReadyStateChange { readyState in print("XHR onReadyStateChange") } .send() ওয়েবসকেট import WebSocket let webSocket = WebSocket("wss://echo.websocket.org").onOpen { print("ws connected") }.onClose { (closeEvent: CloseEvent) in print("ws disconnected code: \(closeEvent.code) reason: \(closeEvent.reason)") }.onError { print("ws error") }.onMessage { message in print("ws message: \(message)") switch message.data { case .arrayBuffer(let arrayBuffer): break case .blob(let blob): break case .text(let text): break case .unknown(let jsValue): break } } Dispatch.asyncAfter(2) { // send as simple string webSocket.send("Hello from SwifWeb") // send as Blob webSocket.send(Blob("Hello from SwifWeb")) } কনসোল সহজ জাভাস্ক্রিপ্টে এর সমতুল্য print(“Hello world“) console.log('Hello world') পদ্ধতিগুলিও ভালবাসা দিয়ে মোড়ানো হয় ❤️ কনসোল Console.dir(...) Console.error(...) Console.warning(...) Console.clear() সরাসরি সম্প্রচার লাইভ প্রিভিউ কাজ করতে আপনি চান প্রতিটি ফাইলে WebPreview ক্লাস ঘোষণা করুন। class IndexPage: PageController {} class Welcome_Preview: WebPreview { @Preview override class var content: Preview.Content { Language.en Title("Initial page") Size(640, 480) // add here as many elements as needed IndexPage() } } এক্সকোড অনুগ্রহ করে নির্দেশাবলী পড়ুন। এটি চতুর কিন্তু সম্পূর্ণরূপে কার্যকর সমাধান 😎 সংগ্রহস্থল পৃষ্ঠায় ভিএসসিকোড ভিতরে যান এবং অনুসন্ধান করুন। VSCode এর এক্সটেনশনে ওয়েবার এটি ইনস্টল হয়ে গেলে (বা লিনাক্স/উইন্ডোজে ) টিপুন। Cmd+Shift+P Ctrl+Shift+P খুঁজুন এবং চালু করুন। Webber Live Preview ডানদিকে, আপনি লাইভ প্রিভিউ উইন্ডো দেখতে পাবেন এবং যখনই আপনি ক্লাস ধারণ করা ফাইলটি সংরক্ষণ করবেন তখন এটি রিফ্রেশ হবে। ওয়েবপ্রিভিউ জাভাস্ক্রিপ্ট অ্যাক্সেস এটি এর মাধ্যমে উপলব্ধ যা এর ভিত্তি। JavaScriptKit SwifWeb পড়ুন আপনি কিভাবে আছেন। অফিসিয়াল ভান্ডারে সম্পদ আপনি প্রকল্পের ভিতরে , , , , এবং অন্য কোন স্ট্যাটিক সম্পদ যোগ করতে পারেন। css js png jpg কিন্তু বা চূড়ান্ত ফাইলে এগুলি উপলব্ধ করার জন্য আপনাকে এ এইভাবে ঘোষণা করতে হবে ডিবাগের সময় রিলিজ প্যাকেজ.swift- .executableTarget(name: "App", dependencies: [ .product(name: "Web", package: "web") ], resources: [ .copy("css/*.css"), .copy("css"), .copy("images/*.jpg"), .copy("images/*.png"), .copy("images/*.svg"), .copy("images"), .copy("fonts/*.woff2"), .copy("fonts") ]), পরে আপনি সেগুলি অ্যাক্সেস করতে সক্ষম হবেন যেমন Img().src(“/images/logo.png“) ডিবাগিং নিম্নলিখিত উপায়ে চালু করুন ওয়েবার webber serve PWA মোডে চালু করতে webber serve -t pwa -s Service অতিরিক্ত পরামিতি ডিবাগ করার উদ্দেশ্যে কনসোলে আরও তথ্য দেখানোর জন্য বা -v --verbose ডিফল্ট 8888 এর পরিবর্তে 443 পোর্টে ওয়েবার সার্ভার শুরু করতে বা -p 443 --port 443 স্বয়ংক্রিয়ভাবে পছন্দসই ব্রাউজার খুলতে, ডিফল্টরূপে এটি কোনো খোলে না --browser chrome/safari স্থানীয়ভাবে পরিষেবা কর্মীদের ডিবাগ করার জন্য প্রয়োজন, অন্যথায় তারা কাজ করে না --browser-self-signed ছদ্মবেশী মোডে ব্রাউজারের অতিরিক্ত উদাহরণ খুলতে, শুধুমাত্র ক্রোমের সাথে কাজ করে --browser-incognito তাই আপনার অ্যাপটিকে ডিবাগ মোডে তৈরি করতে, স্বয়ংক্রিয়ভাবে ক্রোমে এটি খুলুন এবং যখনই আপনি কোনও ফাইল পরিবর্তন করেন তখনই স্বয়ংক্রিয়ভাবে ব্রাউজার রিফ্রেশ করুন এইভাবে চালু করুন এসপিএর জন্য webber serve --browser chrome বাস্তব PWA পরীক্ষার জন্য webber serve -t pwa -s Service -p 443 --browser chrome --browser-self-signed --browser-incognito প্রাথমিক অ্যাপ লোড হচ্ছে আপনি প্রাথমিক লোডিং প্রক্রিয়া উন্নত করতে চাইতে পারেন। এর জন্য প্রজেক্টের ভিতরে ফোল্ডার খুলুন এবং ফাইলটি সম্পাদনা করুন। .webber/entrypoint/dev index.html এটিতে খুব দরকারী শ্রোতাদের সাথে প্রাথমিক HTML কোড রয়েছে: । WASMLoadingStarted WASMLoadingStartedWithoutProgress WASMLoadingProgress WASMLoadingError আপনি আপনার কাস্টম স্টাইল বাস্তবায়ন করতে চান এমন যাই হোক না কেন আপনি সেই কোডটি সম্পাদনা করতে পারবেন 🔥 আপনি যখন নতুন বাস্তবায়ন শেষ করবেন তখন সেটিকে ফোল্ডারে সংরক্ষণ করতে ভুলবেন না .webber/entrypoint/release বিল্ডিং রিলিজ PWA-এর জন্য শুধু বা চালান। webber release webber release -t pwa -s Service তারপর ফোল্ডার থেকে কম্পাইল করা ফাইলগুলিকে ধরুন এবং আপনার সার্ভারে আপলোড করুন৷ .webber/release কিভাবে স্থাপন করতে হয় আপনি যেকোনো স্ট্যাটিক হোস্টিংয়ে আপনার ফাইল আপলোড করতে পারেন। হোস্টিং ফাইলের জন্য সঠিক কন্টেন্ট-টাইপ প্রদান করা উচিত! ওয়াসম হ্যাঁ, সঠিক শিরোনাম থাকা খুবই গুরুত্বপূর্ণ বিষয়বস্তু-প্রকার: ফাইলের জন্য , অন্যথায় দুর্ভাগ্যবশত ব্রাউজার আপনার WebAssembly অ্যাপ্লিকেশন লোড করতে সক্ষম হবে না। wasm Content-Type: application/wasm উদাহরণস্বরূপ ফাইলগুলির জন্য সঠিক সামগ্রী-প্রকার প্রদান করে না তাই দুর্ভাগ্যবশত এটিতে WebAssembly সাইটগুলি হোস্ট করা অসম্ভব৷ GithubPages wasm Nginx আপনি যদি nginx-এর সাথে আপনার নিজের সার্ভার ব্যবহার করেন, তাহলে খুলুন এবং এতে রেকর্ড যদি হ্যাঁ তাহলে আপনি যেতে ভাল! /etc/nginx/mime.types application/wasm wasm; উপসংহার আমি আশা করি আজ আমি আপনাকে অবাক করে দিয়েছি এবং আপনি অন্তত SwifWeb-এ একবার চেষ্টা করবেন এবং সর্বাধিক আপনার পরবর্তী বড় ওয়েব প্রকল্পের জন্য এটি ব্যবহার করা শুরু করবেন! অনুগ্রহ করে যেকোনো একটিতে অবদান রাখতে এবং তাদের সবাইকে ⭐️তারকা দেওয়ার জন্য নির্দ্বিধায়! সুইফওয়েব লাইব্রেরিগুলির রয়েছে যেখানে আপনি বিশাল সমর্থন পেতে পারেন, ছোট টিউটোরিয়াল পড়তে পারেন এবং যে কোনও আসন্ন আপডেট সম্পর্কে প্রথমে অবহিত হতে পারেন! আমাদের সাথে আপনাকে দেখতে ভাল হবে! ডিসকর্ডে আমার একটি দুর্দান্ত সুইফ্টস্ট্রিম সম্প্রদায় এটি মাত্র শুরু, তাই SwifWeb সম্পর্কে আরও নিবন্ধের জন্য সাথে থাকুন! আপনার বন্ধুদের বলুন!