<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by John Viskul on Medium]]></title>
        <description><![CDATA[Stories by John Viskul on Medium]]></description>
        <link>https://medium.com/@johnviskul?source=rss-70c1e52e4be6------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/0*1h8vDUn1H2VOhdN6.</url>
            <title>Stories by John Viskul on Medium</title>
            <link>https://medium.com/@johnviskul?source=rss-70c1e52e4be6------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Tue, 19 May 2026 04:00:40 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@johnviskul/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[มาเริ่มสร้าง Angular 4 พร้อม Server-side Rendering กันเถอะ!]]></title>
            <link>https://medium.com/fungjai/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%A3%E0%B8%B4%E0%B9%88%E0%B8%A1%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-angular-4-%E0%B8%9E%E0%B8%A3%E0%B9%89%E0%B8%AD%E0%B8%A1-server-side-rendering-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-46000eea316f?source=rss-70c1e52e4be6------2</link>
            <guid isPermaLink="false">https://medium.com/p/46000eea316f</guid>
            <category><![CDATA[angular-cli]]></category>
            <category><![CDATA[angular-4]]></category>
            <category><![CDATA[preboot]]></category>
            <category><![CDATA[ssrs]]></category>
            <category><![CDATA[angular]]></category>
            <dc:creator><![CDATA[John Viskul]]></dc:creator>
            <pubDate>Tue, 05 Sep 2017 04:55:32 GMT</pubDate>
            <atom:updated>2017-09-05T04:55:32.197Z</atom:updated>
            <content:encoded><![CDATA[<p>อย่างที่รู้กันว่า <strong>Angular </strong>เป็น Single Page Application (<strong>SPA</strong>) framework ที่ค่อนข้างได้รับความนิยมในหลายปีที่ผ่านมา ซึ่งสามารถจัดการกับหน้าตาของฝั่ง client ได้เป็นอย่างดี แต่อย่างไรก็ตาม <strong>Angular </strong>เองก็ยังมีปัญหาเล็กน้อยเกี่ยวกับ index ที่แสดงบน <strong>search engines</strong></p><p>ปัญหานี้เกิดขึ้นจาก <strong>search engines</strong> และ <strong>social networks</strong> อย่าง <strong>Google</strong> , <strong>Facebook</strong> และ <strong>Twitter</strong> ต่างดึงเอา<strong> plain HTML</strong> เพื่อนำ <strong>meta tags</strong> และข้อมูลบางส่วนไปแสดง โดย search engines และบรรดา social networks ไม่ได้ดึงส่วนเนื้อหาที่ <strong>JavaScript</strong> สร้างขึ้นภายหลัง ผลลัพธ์ที่ได้จึงเกิดขึ้นดังภาพ</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/599/1*2YZ0-lIiBj3uEMcUtmP0zg.png" /><figcaption>ผลการค้นหาจาก http://www.google.com</figcaption></figure><p>บทความนี้จึงขอพูดถึงการทำ <strong>Angular </strong>app เบื้องต้น ตั้งแต่เริ่มต้นสร้างโปรเจค จนพร้อมใช้งานได้จริงบนเซิร์ฟเวอร์ พร้อมการทำ <strong>Server-side Rendering </strong>(SSR) ซึ่งในบทความนี้จะมีเนื้อหาที่ประกอบด้วย</p><ul><li>Angular 4</li><li>Angular CLI</li><li>Angular Unversal</li><li>แนะนำ Meta Service</li><li>Preboot</li></ul><p><strong>เรามาเริ่มกันเลย!!</strong></p><h4>เริ่มสร้างโปรเจค โดย <a href="https://cli.angular.io/">Angular CLI</a></h4><p>เริ่มจากติดตั้ง Angular CLI ลงบนเครื่องของเราในเวอร์ชั่นล่าสุด</p><pre>npm install -g @angular/cli@latest</pre><p>หลังจากนั้นสร้างโปรเจคของเราด้วย CLI -<em>ในบทความนี้เราจะใช้ชื่อว่า my-app</em></p><pre>ng new my-app<br>cd my-app<br>npm install -D ts-node<br>npm install -S @angular/platform-server @angular/animations</pre><p>เมื่อติดตั้งเรียบร้อยแล้ว ให้เพิ่ม script ในไฟล์ ดังต่อไปนี้</p><h4>src/app/app.module.ts</h4><pre><em>...</em><br><strong>import { FormsModule } from &#39;@angular/forms&#39;;<br>import { HttpModule } from &#39;@angular/http&#39;;<br></strong><br><em>@NgModule({<br>    ...<br>    imports: [<br>        BrowserModule</em><strong><em>.</em>withServerTransition({appId: &#39;my-app&#39;}),</strong><br>       <strong> FormsModule,    <br>        HttpModule</strong><br> <em>   ],<br>...<br></em></pre><h4>src/tsconfig.app.json</h4><pre><em>...<br>&quot;exclude&quot;: [</em><br>   <strong> &quot;server.ts&quot;,</strong><br><em>    ...<br>]</em></pre><h4><em>tsconfig.j</em>son</h4><pre><em>{<br>  ...<br>  &quot;compilerOptions&quot;: {<br>    ...<br>    </em>&quot;lib&quot;: [<br>      &quot;es2016&quot;,<br>      &quot;dom&quot;<br>    ]<br>  <em>}</em><strong><em>,</em><br>  &quot;angularCompilerOptions&quot;: {<br>    &quot;genDir&quot;: &quot;./dist/ngfactory&quot;,<br>    &quot;entryModule&quot;: &quot;./src/app/app.module#AppModule&quot;<br>  }</strong><br><em>}</em></pre><h4>package.json</h4><pre>{<br>  ...<br>  &quot;scripts&quot;: {<br>    ...<br><strong>    &quot;prestart&quot;: &quot;ng build --prod &amp;&amp; ngc&quot;,<br>    &quot;start&quot;: &quot;ts-node src/server.ts&quot;,<br>    &quot;start:client&quot;: &quot;ng serve&quot;<br></strong>  },<br>  ...<br>}</pre><p><strong>สร้างไฟล์ src/app/app.server.module.ts</strong></p><pre>import { NgModule } from &#39;@angular/core&#39;;<br>import { ServerModule } from &#39;@angular/platform-server&#39;;<br>import { AppModule } from &#39;./app.module&#39;;<br>import { AppComponent } from &#39;./app.component&#39;;</pre><pre>@NgModule({<br>  imports: [<br>    ServerModule,<br>    AppModule<br>  ],<br>  bootstrap: [AppComponent]<br>})<br>export class AppServerModule { }</pre><p><strong>สร้างไฟล์ src/server.ts</strong></p><pre>import &#39;reflect-metadata&#39;;<br>import &#39;zone.js/dist/zone-node&#39;;<br>import { platformServer, renderModuleFactory } from &#39;@angular/platform-server&#39;<br>import { enableProdMode } from &#39;@angular/core&#39;<br>import { AppServerModuleNgFactory } from &#39;../dist/ngfactory/src/app/app.server.module.ngfactory&#39;<br>import * as express from &#39;express&#39;;<br>import { readFileSync } from &#39;fs&#39;;<br>import { join } from &#39;path&#39;;</pre><pre>const PORT = 4000;</pre><pre>enableProdMode();</pre><pre>const app = express();</pre><pre>let template = readFileSync(join(__dirname, &#39;..&#39;, &#39;dist&#39;, &#39;index.html&#39;)).toString();</pre><pre>app.engine(&#39;html&#39;, (_, options, callback) =&gt; {<br>  const opts = { document: template, url: options.req.url };</pre><pre>renderModuleFactory(AppServerModuleNgFactory, opts)<br>    .then(html =&gt; callback(null, html));<br>});</pre><pre>app.set(&#39;view engine&#39;, &#39;html&#39;);<br>app.set(&#39;views&#39;, &#39;src&#39;)</pre><pre>app.get(&#39;*.*&#39;, express.static(join(__dirname, &#39;..&#39;, &#39;dist&#39;)));</pre><pre>app.get(&#39;*&#39;, (req, res) =&gt; {<br>  res.render(&#39;index&#39;, { req });<br>});</pre><pre>app.listen(PORT, () =&gt; {<br>  console.log(`listening on http://localhost:${PORT}!`);<br>});</pre><p>หลังจากนั้นลอง run โปรเจคของเราโดยใช้คำสั่ง</p><pre>npm run start</pre><p>และเข้าไปที่ <a href="http://localhost:4000/">http://localhost:4000</a> จะได้เว็บของเรา</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*OjuKWMRqYe3iFzvdy8Cb5A.png" /><figcaption>หน้าตาของเว็บไซต์ที่ได้จาก Angular CLI</figcaption></figure><p>หน้าตาของเว็บที่ได้นั้น เหมือนกับโปรเจคที่ถูกสร้างด้วย CLI ทุกประการ ซึ่งสามารถเปรียบเทียบกับโปรเจคธรรมดาที่ไม่ใช้ Angular Universal ได้ โดยใช้คำสั่ง</p><pre>npm run start:client</pre><p>และเข้าไปที่ <a href="http://localhost:4000/">http://localhost:4200</a> ซึ่งเป็น Angular ที่ไม่มี Angular universal ซึ่งสองส่วนนี้แต่ต่างกันตรงที่ Angular Universal จะทำหน้าที่เป็น server-side render ทำให้เนื้อหาภายในเว็บไซต์ถูก render ออกมาเป็น plain HTML ไว้ตั้งแต่แรก ช่วยลดช่องโหว่ของ SPA ได้เป็นอย่างดี</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*5roA9y-IjJSdsi0RlKYb2A.png" /><figcaption>ภาพเปรียบเทียบ Plain HTML ที่ได้จากโปรเจค</figcaption></figure><h4><strong>ทำ Meta tag ให้ง่ายขึ้น</strong></h4><p>การตั้ง meta tag ของเว็บไซต์ มีไว้เพื่อจัดการกับ index ใน Search Engine สามารถจัดการด้วยการสร้าง service ไว้คอยควบคุม meta ในไซต์ต่างๆของเรา ซึ่ง Angular ก็มี service ที่ช่วยควบคุม meta tag ให้เป็นเรื่องที่ไม่ยุ่งยากอีกต่อไป โดยสามารถหาอ่านได้ใน <a href="https://angular.io/api/platform-browser/Meta">Meta Docs ของ Angular</a></p><p>ส่วนการทำ <strong>Search Engine Optimization</strong>(SEO) นั้นขึ้นอยู่กับเทคนิคของแต่ละคน ยิ่งเราใส่คำที่ถูกค้นหา(keyword) ตรงกับเนื้อหามากเท่าไหร่ เว็บไซต์ของเราก็ติดอันดับหนึ่งของ search engine ได้ไม่ยาก</p><h4><strong>เพิ่มประสิทธิภาพอีกนิดด้วย Preboot</strong></h4><p>เมื่อโปรเจคของเรามีขนาดใหญ่ขึ้น มีความซับซ้อนมากขึ้น เว็บก็จะโหลดช้าลงเป็นปกติ หนึ่งในปัญหาที่เกิดขึ้นเมื่อเว็บไซต์เรามี Server-side Rendering คือ เกิด transition ระหว่าง server-side webview ในตอนแรก และเมื่อ javascript ทำงานก็จะแสดง client-side webview ขึ้นมา ถึงจะเป็นเรื่องเล็กน้อย แต่มีผลต่อประสบการณ์การใช้งานของผู้ใช้(User Experience)พอสมควร</p><p>การแก้ปัญกา transition ดังกล่าวสามารถใช้ <a href="https://github.com/angular/preboot">Preboot</a> เข้ามาช่วยจัดการได้ ซึ่งสามารถอ่านเพิ่มเติมได้ที่ <a href="https://github.com/angular/preboot">https://github.com/angular/preboot</a></p><p>หรือจะทำตามบทความนี้ก็ได้เช่นกัน สำหรับในบทความนี้เพียงต้องการ freeze เว็ปเพจก่อนหน้าไว้ระหว่าง client-side webview กำลังโหลด และค่อยแสดงผลเมื่อโหลด client-side webview เสร็จทีเดียว ซึ่งเริ่มจากติดตั้ง preboot ลงไปในโปรเจคของเรา</p><pre>npm i preboot --save</pre><p>หลังจากนั้นเพิ่ม code เข้าไปในโปรเจคของเราเพียง 2 บรรทัด</p><p><strong>src/app/app.server.module.ts</strong></p><pre>...<br><strong>import { ServerPrebootModule } from &#39;preboot/server&#39;;</strong></pre><pre><em>@NgModule({<br>  imports: [<br>    ServerModule,<br>    AppModule,</em><br>   <strong> ServerPrebootModule.recordEvents({ appRoot: &#39;my-app&#39; })</strong><br> <em> ],<br>  bootstrap: [AppComponent]<br>})<br>export class AppServerModule { }</em></pre><p>ท่านี้เว็บเราก็จะสมบูรณ์ขี้น พร้อมใช้งานอย่างราบรื่น ดูมีระดับตามสไตล์ของ Angular Universal</p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*oCWkf7ODHBGKpcGHMzvSkg.png" /><figcaption>ภาพแสดงการทำงานของ universal จาก <a href="https://medium.com/capital-one-developers/a-peek-into-the-open-source-technologies-behind-capitalone-com-80bae5ca9279">บทความของ Michi Kono</a></figcaption></figure><h3>สรุป</h3><p><strong>Angular Universal </strong>เป็น <strong>Server-side Renderer</strong> ซึ่งจะสร้าง Server-side webview เป็น <strong>Plain HTML</strong> เพื่อแสดงเนื้อหาในเว็บไซต์ของเราเมื่อถูกค้นหาจาก <strong>Search Engine</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/proxy/1*gbIZ0N1Gkv1KYFDlh_eeIg.png" /><figcaption>ภาพแสดงการทำงานของ universal จาก <a href="https://medium.com/capital-one-developers/a-peek-into-the-open-source-technologies-behind-capitalone-com-80bae5ca9279">บทความของ Michi Kono</a></figcaption></figure><p>ซึ่งบทความนี้เป็นเพียงการแนะนำคุณสมบัติหนึ่งของ Angular universal สำหรับนำไปใช้งานเบื้อต้น แน่นอนว่าในการสร้างโปรเจคหนึ่งๆต้องใช้เครื่องมือและเทคนิคอีกมากมาย ขึ้นอยู่กับจุดประสงค์ของเว็ปไซต์และคุณภาพที่ต้องการ ซึ่งเครื่องมือในยุคสมัยนี้พัฒนาอย่างรวดเร็ว และแทบจะตลอดเวลา ดังนั้นเราควรติดตามเทคโนโลยีที่ใช้งานอยู่เสมอ และ Angular ก็เช่นกัน</p><p><strong>อ้างอิง</strong></p><p><a href="https://medium.com/@evertonrobertoauler/angular-4-universal-app-with-angular-cli-db8b53bba07d">Angular 4 universal app with @angular/cli</a></p><p><a href="https://netbasal.com/exploring-the-new-meta-service-in-angular-version-4-b5ba2403d3e6">Exploring The New Meta Service in Angular Version 4</a></p><p><a href="https://github.com/angular/preboot">Preboot on GitHub</a></p><p><a href="https://medium.com/capital-one-developers/a-peek-into-the-open-source-technologies-behind-capitalone-com-80bae5ca9279">A Peek Into the Open Source Technologies Behind CapitalOne.com</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=46000eea316f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/fungjai/%E0%B8%A1%E0%B8%B2%E0%B9%80%E0%B8%A3%E0%B8%B4%E0%B9%88%E0%B8%A1%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87-angular-4-%E0%B8%9E%E0%B8%A3%E0%B9%89%E0%B8%AD%E0%B8%A1-server-side-rendering-%E0%B8%81%E0%B8%B1%E0%B8%99%E0%B9%80%E0%B8%96%E0%B8%AD%E0%B8%B0-46000eea316f">มาเริ่มสร้าง Angular 4 พร้อม Server-side Rendering กันเถอะ!</a> was originally published in <a href="https://medium.com/fungjai">Fungjai</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>