From c9d3e71422331ab5a7c04cd1d5748a4a2ce23390 Mon Sep 17 00:00:00 2001 From: khoaxuantu <68913255+khoaxuantu@users.noreply.github.com> Date: Mon, 22 Jan 2024 00:15:03 +0700 Subject: [PATCH 1/6] style: update blogs --- src/components/layouts/blog.tsx | 2 +- src/css/markdown.css | 3 + src/css/markdown.css.map | 2 +- src/css/scss/markdown.scss | 4 + src/markdown/react_bun_boilerplate.md | 165 ++++++++++++++++++++ src/markdown/uncommon_javascript_notes.md | 16 -- src/markdown/uncommon_javascript_notes_1.md | 66 ++++---- 7 files changed, 206 insertions(+), 52 deletions(-) create mode 100644 src/markdown/react_bun_boilerplate.md diff --git a/src/components/layouts/blog.tsx b/src/components/layouts/blog.tsx index 5239f4a..9a86e23 100644 --- a/src/components/layouts/blog.tsx +++ b/src/components/layouts/blog.tsx @@ -21,7 +21,7 @@ function BlogLayout() {
- +
); } diff --git a/src/css/markdown.css b/src/css/markdown.css index b0ee8ae..abc8488 100644 --- a/src/css/markdown.css +++ b/src/css/markdown.css @@ -8,6 +8,9 @@ list-style-type: revert; line-height: 1.5rem; } +.single-blog-wrapper h1 { + padding-top: 3rem; +} .single-blog-wrapper code, .single-blog-wrapper pre { border-radius: 5px; background-color: #282c34; diff --git a/src/css/markdown.css.map b/src/css/markdown.css.map index dd9e787..85daade 100644 --- a/src/css/markdown.css.map +++ b/src/css/markdown.css.map @@ -1 +1 @@ -{"version":3,"sourceRoot":"","sources":["scss/general/_var.scss","scss/markdown.scss"],"names":[],"mappings":"AAAQ;AACA;AACA;AAKR;ACAI;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA,kBAde;EAef,OAdU;;AAiBd;EACI;EACA;EACA;EACA;EACA,aDfS;ECgBT;;AAEA;EACI;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;;AAIR;EAEI,aD9DQ","file":"markdown.css"} \ No newline at end of file +{"version":3,"sourceRoot":"","sources":["scss/general/_var.scss","scss/markdown.scss"],"names":[],"mappings":"AAAQ;AACA;AACA;AAKR;ACAI;EACI;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA,kBAlBe;EAmBf,OAlBU;;AAqBd;EACI;EACA;EACA;EACA;EACA,aDnBS;ECoBT;;AAEA;EACI;;AAIR;EACI;EACA;EACA;;AAEA;EACI;;AAIR;EACI;EACA;EACA;EACA;EACA;;AAGJ;EACI;;AAGJ;EACI;EACA;;AAGJ;EACI;;AAGJ;EACI;;;AAIR;EAEI,aDlEQ","file":"markdown.css"} \ No newline at end of file diff --git a/src/css/scss/markdown.scss b/src/css/scss/markdown.scss index 66b1f2e..d5d9afc 100644 --- a/src/css/scss/markdown.scss +++ b/src/css/scss/markdown.scss @@ -12,6 +12,10 @@ $codeinline-background: #f6f8fa; line-height: 1.5rem; } + h1 { + padding-top: 3rem; + } + code, pre { border-radius: 5px; background-color: $codeblock-background; diff --git a/src/markdown/react_bun_boilerplate.md b/src/markdown/react_bun_boilerplate.md new file mode 100644 index 0000000..3aedd89 --- /dev/null +++ b/src/markdown/react_bun_boilerplate.md @@ -0,0 +1,165 @@ +# Introduction + +> Many people are hyped with Bun for its performance and new features compared with +> Node. One of them is .jsx and .tsx file support with its internal transpiler, which help creating a React app by Bun becomes more convenient. But the problem here is to have a +> boilerplate to optimize the feature for creating React app. + +I came up with that idea when reading the `JSX` runtime of Bun. If we can exclude the works of Babel and Webpack, then we can reduce our build time and bundle's size dramatically. + +I also know that there has already been some templates to create a React app in Bun, such as: + +```bash +bun create react-app appname +``` + +But the template like above simply uses Bun to run `npx create-react-app` and install all +the preset dependencies. It means the project will keep using Babel and Webpack; that's not +what I want 🙁 + +Then one day, I find out the appropriate templates in the `create-templates` repository of +the Bun community (you can check them out via this [link](https://github.com/bun-community/create-templates)), which are `react-ssr` and +`react`. Looking at the templates' code, it turned out that I barely understood what each line +actually does. I was desperate to discover the true techniques behind them so that came +up with an idea is to create a new custom React app boilerplate with Bun. To simulate +each technique then I would be able to understand them. + +> Thus, why not to try? + +Below, I will share what I have learned and recalled from my custom boilerplate. + + +# Table of Contents + +- How are static contents served in a web +- How the server-side rendering delivers React components +- Inside the FileSystemRoute, refers to NextJS's routing +- About client-side rendering +- Cusom the console.log, manually custom a welcome console log + + +# How are the static contents served in a web + +The basics comes first, or, as it should be said, everything is built on top of the basics. +Sometimes, we are just too focused on fancy stuff that we forget why there are the +things called fundamentals. This time, it hit me hard. + +I found the following code in the [`react-ssr`](https://github.com/bun-community/create-templates/blob/main/react-ssr/dev.tsx) template: + +```ts +function serveFromDir(config: { + directory: string; + path: string; +}): Response | null { + let basePath = path.join(config.directory, config.path); + const suffixes = ['', '.html', 'index.html']; + + for (const suffix of suffixes) { + try { + const pathWithSuffix = path.join(basePath, suffix); + const stat = statSync(pathWithSuffix); + if (stat && stat.isFile()) { + return new Response(Bun.file(pathWithSuffix)); + } + } catch (err) {} + } + + return null; +} + +export default { + async fetch(request) { + ... + let reqPath = new URL(request.url).pathname; + ... + // check public + const publicResponse = serveFromDir({ + directory: PUBLIC_DIR, + path: reqPath, + }); + if (publicResponse) return publicResponse; + ... + } +} satisfies ServeOptions; +``` + +Like a habit, my head came up with the `WTF`, that thing was frightening me. Although +it looks familiar, somehow I could not understand it at first. + +> So... I must put myself through what frightening me huh... + +It took a long time for me just to regain calm and read the code line by line, and finally, +I could break the code into the following pseudocode: + +``` +Define function serveFromDir(directory, filepath): + basepath -> join directory and file path together + suffixes -> ['', '.html', 'index.html'] as list + + For each suffix in the suffixes list: + Try do: + pathWithSuffix -> join basePath and suffix together + stat -> get pathWithSuffix's statistic + + If stat exists and stat is a file: + Return a Response with the blob object of the file located in pathWithSuffix + End if + Catch any error + End try + End for + + Return null +End define + +In Bun serve option + In async fetch(): + reqPath -> URL's pathname of request.url + + publicResponse -> serveFromDir(PUBLIC_DIR, reqPath) + If publicResponse exists (not null): + Return publicResponse as Response + end if + end fetch() +end Bun serve otion +``` + +Typically, the `serveFromDir()` method resolves the directory and filepath, then +checks the statistic in the resolved path. If it knows the statistic exists and +there is a file as the resolved path, it will return a `Response` object containing the +file. + +In the Bun serve option, we use the `serveFromDir()` to map the request pathname to +the specific public folder. Thus, if we request to get public content, for +example, at `http://localhost:3000/image.jpg`, the flow will go like this: + +1. The `reqPath` is assigned to `/image.jpg` +2. Assume we set the `PUBLIC_DIR` to `__dirname + /public` +3. In the `serveFromDir()`, we will have the `basePath` which is equivalent to + `__dirname + /public/image.jpg`. +4. In the suffix `''`, we set the `pathWithSuffix` to the same with `basePath`, + so the code will check the `image.jpg` in the `public` folder. +5. Assuming there is an `image.jpg` file in the `public` folder, it will return a `Response` + object containing the blob object of that file. +6. Finally, this `Response` object is sent to the client browser. + +Recall when we wrote our `index.html` for the first time, It turns out that everything follows the same concept: +- We request to the server for content. +- The server resolves the request path, then checks the file system. +- The server returns status `200` if it finds out the content, or status `404` if the content + is not found. + +We can try to start a http server via the popular [http-server](https://www.npmjs.com/package/http-server) +command in any static content folder, we will get the whole file system displayed on +the browser. + +The difference here is just in the Bun serve option; we have specified a specific +directory for the app to look into, not only a root directory. + +> That's why I find the code so familiar huh... + + +# How the server-side rendering delivers React components + + + +> ... Updating + diff --git a/src/markdown/uncommon_javascript_notes.md b/src/markdown/uncommon_javascript_notes.md index f0705ef..4b5e37c 100644 --- a/src/markdown/uncommon_javascript_notes.md +++ b/src/markdown/uncommon_javascript_notes.md @@ -48,7 +48,6 @@ have very fundamental topics, instead, it contains concepts that I can easily mi for looking up JavaScript basics, you can refer to [javascript.info tutorials](https://javascript.info/) directly or [MDN (Mozilla) JavaScript manual](https://developer.mozilla.org/en-US/docs/Web/JavaScript). -

--- @@ -109,7 +108,6 @@ directly or [MDN (Mozilla) JavaScript manual](https://developer.mozilla.org/en-U + [Dynamic imports](#dynamic-imports)
-

--- @@ -323,7 +321,6 @@ const func = () => {} ```
-

## Code quality ### Polyfills and transpilers @@ -334,7 +331,6 @@ The scripts that update/add new functions. **Transpilers**\ Translate code to a different version. -

## Objects: the basics ### Objects @@ -356,7 +352,6 @@ Translate code to a different version. + `Symbol.keyFor(sym)`
-

## More about data types ### Iterables @@ -564,7 +559,6 @@ JSON.parse(str, function(key, value) { ```
-

## Advanced working with functions @@ -974,7 +968,6 @@ user.sayNow("Hello"); ```
-

## Object properties configuration @@ -1010,7 +1003,6 @@ Object.defineProperties(obj, { ```
-

## Prototypes, inheritance @@ -1120,7 +1112,6 @@ obj.join = Array.prototype.join; console.log(obj.join(',')); // Hello,World! ```
-

## Classes @@ -1153,7 +1144,6 @@ class MyClass { ```
-

## Error handling @@ -1296,7 +1286,6 @@ try { ```
-

## Promises, async/await @@ -1907,7 +1896,6 @@ f().catch(alert); // TypeError: failed to fetch ```
-

## Generators, advanced iteration @@ -2223,7 +2211,6 @@ let range = { ```
-

## Modules @@ -2312,18 +2299,15 @@ let module = await import(modulePath); ```
-

--- ## References - [Javascript.info](https://javascript.info/) - Part 1: The JavaScript language - [MDN Web Docs - Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript) - JavaScript -

--- ## Upcoming *Uncommon JavaScript Notes - Browser: Document, Events, Interfaces* - based on javascript.info's [part 2](https://javascript.info/#tab-2). -

diff --git a/src/markdown/uncommon_javascript_notes_1.md b/src/markdown/uncommon_javascript_notes_1.md index 2764810..9e04804 100644 --- a/src/markdown/uncommon_javascript_notes_1.md +++ b/src/markdown/uncommon_javascript_notes_1.md @@ -16,7 +16,6 @@ using JavaScript. It is based on [javascript.info's part 2](https://javascript.i to have a fundamental knowledge of JavaScript. If you are a newbie in JS, let's check out the [javascript.info's part 1](https://javascript.info/#tab-1) first before jumping into this section. -

--- @@ -32,18 +31,17 @@ to have a fundamental knowledge of JavaScript. If you are a newbie in JS, let's + [Node properties: type, tag and contents](#node-properties-type-tag-and-contents) + [Attributes and properties](#attributes-and-properties) + [Modifying the document](#modifying-the-document) - + [Styles and classes](#styles-and-classes) - + [Element sizes and scrolling](#element-sizes-and-scrolling) - + [Window sizes and scrolling](#window-sizes-and-scrolling) - + [Coordinates](#coordinates) + + [Styles and classes](#styles-and-classes) + + [Element sizes and scrolling](#element-sizes-and-scrolling) + + [Window sizes and scrolling](#window-sizes-and-scrolling) + + [Coordinates](#coordinates) - [Introduction to Events](#introduction-to-events) - + [Introduction to browser events](#introduction-to-browser-events) - + [Bubbling and capturing](#bubbling-and-capturing) + + [Introduction to browser events](#introduction-to-browser-events) + + [Bubbling and capturing](#bubbling-and-capturing) + [Event delegation](#event-delegation) -

--- @@ -228,7 +226,7 @@ corresponding DOM object. All operations on the DOM start with the `document` ob
-![DOM nodes](../images/blogs/uncommon_javascript_notes_1/1.webp "DOM nodes") +![DOM nodes](/images/blogs/uncommon_javascript_notes_1/1.webp "DOM nodes")
@@ -292,7 +290,7 @@ So let's see more navigation links that only take *element nodes* into account:
-![element nodes](../images/blogs/uncommon_javascript_notes_1/2.webp "element nodes") +![element nodes](/images/blogs/uncommon_javascript_notes_1/2.webp "element nodes")
@@ -362,7 +360,7 @@ and other DOM nodes inherit from it.
-![DOM node classes](../images/blogs/uncommon_javascript_notes_1/3.webp "DOM node classes") +![DOM node classes](/images/blogs/uncommon_javascript_notes_1/3.webp "DOM node classes")
@@ -724,7 +722,7 @@ elem.remove() > All insertion methods automatically remove the node from the old place #### Cloning nodes: cloneNode -The call `elem.cloneNode(true)` creates a "deep" clone of the element - with all attributes and +The call `elem.cloneNode(true)` creates a "deep" clone of the element - with all attributes and subelements. If we call `elem.cloneNode(false)`, then the clone is made without child elements. ```javascript let div2 = div.cloneNode(true); // clone the existing div @@ -741,7 +739,7 @@ div.after(div2); // show the clone after the existing div ``` -#### More properties +### More properties - `value` - the value for ``, `