Javascript Structure 1 (โครงสร้าง javascript webapp)

repo นี้เอาไว้เป็นแนวทางสำหรับคนที่กำลังหัดเขียน webapp ด้วย javascript คับ กะไว้ว่าเขียนให้คนที่พอมีพื้นฐานเขียนโปรแกรม / javascript อยู่แล้ว แต่ยังงงๆเรื่องพวก environment /structure ในการประกอบร่างกันเป็นแอพอันนึง

จะมีวิธีการเซตอัพ structure พื้นฐาน และตัวอย่างการใช้ babel + webpack + gulp ในการ compile/transpile โค้ดเราให้มันพร้อมใช้ได้จริงๆ

ผมเองก็พึ่งหัด เพราะงั้นเห็นตรงไหนผิด / ควรแก้ไขก็บอกได้นะ 55

แปะลิ้งที่มีประโยชน์ : http://blog.differential.com/the-javascript-ecosystem-demystified/

1. เริ่มด้วยการ new project

ไปสร้างโฟลเดอร์ที่เราต้องการแล้วพิม npm init โลด มันเป็นคำสั่งสำหรับสร้าง package.json ซึ่งก็คือคอนฟิกของ node project อะแหละ กด enter ไปรัวๆก่อน จนมันเสร็จ เราจะได้ package.json มาเชยชม

2. run javascript ด้วย Node.js

ไปโหลด Node.js มากันก่อนคับ Node.js คือ javascript runtime – คือแต่ก่อน javascript มันรันบน browser อย่างเดียวไง แต่ก็มีคนที่อยากเอามันมารันบนเครื่อง ซึ่งมันก็ใช้ javascript engine ของ Google Chrome อะแหละ ข้อดีของ Node ที่เค้าโฆษณาคือ non blocking IO/ asynchronous ซึ่งเอาจริงๆ ผมก็ยังไม่รู้สึกว่ามันแตกต่างขนาดที่ต้องย้ายจาก java มาใช้ Node นะ แต่ก็เอาเถอะ 55

หลังจากลง node เสร็จ เราก็มาลองเขียน javascript กัน ก่อนอื่นเลยเราต้องรู้ก่อนว่า javascript นั้น มันเป็นภาษา script อยู่แล้ว คือเขียนแล้วรันได้เลย ไม่เหมือนพวก java, c ที่ต้อง compile เป็น .class ถึงจะใช้งานได้จริง

ขั้นแรกที่อยากให้ลองกันคือสร้างไฟล์ main.js ไก่กามาอันนึง โดยมีโค้ดแค่นี้

1
  console.log('Hello Javascript!');

เซฟไว้ตรงไหนก็ได้ เช่น myproj/main.js

เสร็จแล้วไปที่ command prompt / terminal แล้วพิมพ์ node main.js มันจะปริ้นออกมาว่า Hello Javascript!

ทีนี้แอดวานซ์ขึ้นมาหน่อย ลองสร้างอีกไฟล์ ข้างๆกัน ชื่อ car.js

1
2
3
4
5
6
7
  class Car{
    constructor(param){
      console.log(param);
    }
  }

  module.exports = Car;

อันนี้เป็นการสร้าง class Car syntax อาจจะงงๆบ้าง ช่างมันก่อน เอาเป็นว่ามันสร้าง class Car โดยมี constructor รับ parameter มาก็ปริ้นมาดูง่ายๆ

เสร็จแล้วไปแก้ main.js ของเราให้เป็นแบบนี้

1
2
3
var Car = require('./car');

let carObj = new Car("red");

จะเป็นการสร้าง import module car ที่เราสร้างไว้มาเก็บไว้ โดย var Car ในที่นี้จะแทนตัว class Car ส่วน carObj จะเป็นการสร้าง object Car จริงๆขึ้นมาโดยในที่นี้เราใส่ constructor parameter ไปว่า ‘red’

ลองไปรัน main.js ด้วยคำสั่ง node main.js มันน่าจะปริ้นคำว่า red นะ

3. Compile javascript ด้วย Babel

ตัวอย่างข้างบนเป็นการ import module หรือเรียกเท่ห์ๆว่าการจัดการ module system วิธีที่เขียนแบบ require(‘..’) เค้าเรียกว่า Common.js หาอ่านเพิ่มได้ในลิ้งที่ผมแปะข้างบน

ทีนี้มันมีวิธีที่ใหม่กว่า เท่ห์ว่า ดีกว่า(ยังไงวะ) คือวิธีการ import แบบใช้มาตรฐาน ECMAScript2015 หรือ ES6 โดยทำแบบนี้

1
2
3
4
  "use strict";
  import Car from './car';

  let carObj = new Car("red");

ลองเซฟแล้วไปรัน node main.js ดู คราวนี้จะเจอเออเร่อ นั่นเป็นเพราะ node javascript runtime มันยังไม่รองรับคำสั่งนี้นั่นเอง ซึ่งก็เป็นคิวของ babel ที่จะมาช่วยเรา (ให้งงไปกว่าเดิม)

เรื่องของเรื่องคือไอมาตรฐาน ECMAScript2015 มันออกมาได้สักพักแล้วหละ แต่พวก runtime/browser ทั้งหลาย มันยังไม่ support เพราะคนมันน้อยมั้ง มันเลยทำไม่ทัน ทีนี้พวก developer วัยรุ่นอย่างเราๆมันใจร้อนอยากลองของใหม่ไง มันเลยมีคนทำ compiler มาแปลง ES6 ให้เป็น ES5 ให้ runtime มันรันได้ (จะรีบกันไปไหนครับพี่) ทีนี้เราก็สามารถเขียนโปรแกรมเราด้วย Syntax ใหม่ๆได้แล้ว (เพียงแต่ต้องคอมไพล์ก่อนรัน เท่านี้เอง เย้ มันง่ายขึ้นหรือยากขึ้นวะเนี่ย - -)

Babel ก็เป็นหนึ่งใน compiler ที่เค้าฮิตๆกัน นั่นเอง babel มันมีวิธีใช้หลายแบบนะ เช่น import บน <script> tag ใน html แล้วใช้กันตรงนั้นเลยก็ได้ แต่ในที่นี้ผมจะทำแบบฝั่ง server

ก่อนอื่นลง babel กันก่อนด้วยคำสั่ง npm install --save -g babel

  • –save หมายถึง ให้ไปอัพเดท package.json ด้วยว่าโปรเจคนี้มีการใช้ babel เวลา dev คนอื่น รัน npm install npm มันจะไปโหลด babel มาให้ด้วยเลย
  • -g หมายถึง global คือลง babel ไว้เป็น cmd ในคอมเราเลย เห็นในไกด์บอกไม่ต้อง -g ก็รันได้ แต่ผมรันไม่ได้อะ เลยลง global มันเลย

เสร็จแล้ว เราไปรัน babel main.js -o out.js กัน จะเป็นการ compile main.js แล้ว output file คือ out.js เปิด out.js ดูจะพบว่า….. โค้ดมันเหมือนกันเลย!! กำ นั่นเป็นเพราะเราลืมบอก babel นั่นเองไว่ให้ compile เป็น ES5

ให้เราสร้าง .babelrc ไว้ในโปรเจคเราอะแหละ

1
2
3
{
  "presets": ["es2015"]
}

ทีนี้เอาใหม่ รัน babel main.js -o out.js ไปดู out.js จะพบว่าหน้าตามันแปลกไป ดูไม่คุ้นเคย โค้ดโคตรงง ไม่ใช่ที่เราเขียนแน่ๆ ไม่เป็นไร ช่างมัน ลองรัน node out.js ดู คราวนี้จะได้ ‘red’ ออกมาแล้วแหละ เย้

ในการใช้งานจริง เราจะไม่ได้ compile เป็นไฟล์ๆแบบนี้หรอก เราจะคอมไพล์เป็น โฟลเดอร์เลย เหมือน java มันก็คอมไพล์โฟลเดอร์ src แล้วไปออกที่ folder bin อะไรยังงั้น

babel src --out-dir lib

ซึ่งเราจะไม่ได้รันเอง แต่จะใช้ตัว task runner ที่ชื่อ gulp มารันให้อีกที
พอก่อน ขี้เกียจละ

Using slick carousel with Meteor React

This post is about using slick carousel https://github.com/akiran/react-slick with Meteor React framework. It also can apply with other React component that relies on CommonJS.

What you’ll need

So, let’s get started.

I’m learning meteor framework with react.js and trying to put a carousel to my website. I decide to go with slick carousel http://kenwheeler.github.io/slick/ react port which seems easy to use.

Problem is react-slick component made an assumption that we’ll use CommonJS module, like this:

	var React = require('react');
	var Slider = require('react-slick');

which make sense because the carousel comes before meteor see the world.

So, in order to make use or existing react component that relies on CommonJS, I need to add this meteor package : meteor add cosmos:browserify

this browserify will make the require('modulename') things work on client side.

the require is a module loader command which originally is made for node.js server side. Browserify will make this command works on client side

Let’s create a file name /lib/app.browserify.js – the browserify.js suffix is required. Then put this code in it.

//app.browserify.js
//we do not required 'react' here because we will use meteor version
Slider = require('react-slick');

This will make Slider available in global scope so you can use it in your react component.

I'm not sure if lib is a right place to put the browserify file because lib is shared to both server and client whereas browserify is meant to be used for client only. I might move it later

But we don’t have react-slick module yet

Now that we have browserfiy ready in Meteor side, let’s start making use of node package by first adding meteor add meteorhacks:npm and then npm install react-slick. This should list a react-slick module (that we require in previous step) in your package.json. If you run npm list now, You’ll see react-slick as well as react in its dependency.

Now go to your browser and run your code, hopefully there will not be an error like ReferenceError: require is not defined because we already add browserify package.

What you will get is an error : you have multiple copies of React loaded. This is because we already have react package in meteor and it conflicts with npm react that is in dependency or react-slick.

You have multiple copies of React loaded

To solve this, we need to use npm package externalify. Go run npm install externalify in your console. Once it is installed, create a file called /lib/app.browserify.options.json and put this config in it

    {
      "transforms": {
        "externalify": {
          "global": true,
          "external": {
            "react": "React.require",
            "react-dom": "React.require"
          }
        }
      }
    }

This is a browserify transformer which will transfer ‘react’ and ‘react-dom’ require to use meteor’s react version. This will solve you have multiple copies of React loaded error.

Go back to browser and run your code, it should work now but not so nice.

You will need one more component in order to make it work. It’s a stylesheet. To install it, the author suggest us to use bower. Meteor also has a bower package so let’s add it meteor add mquandalle:bower once you install it. create a file .bowerrc in your root folder and put below code it in. This will enable bower command in your command line.

{
  "directory": ".meteor/local/bower"
}

Now run bower init to create a bower.json file. You can spam enter to use default value. After that, bower install --save slick-carousel to install slick-carousel stylesheet. It will be list in bower dependency as well so that other dev can install it.

You’ll need git in your PATH in order to install slick-carousel

THAT’S IT.

Hopefully, your slick carousel should work now. It seems tiredsome for just a carousel but browserify, npm and bower are actually a common tool and can be used for other package/component that you might need in future.

Hope this blog post help you!

Node.js 4 - Passport custom callback

In my previous post, I wrote about how to use passport authentication with Basic Strategy. One thing that bugged me was I cannot return a result right from passport callback. Below is the code from my previous post.

//server.js
var server = restify.createServer();

server.use(restify.bodyParser());
server.use(passport.initialize());

server.get('/users',
  passport.authenticate('basic',{ session: false}),
  function( req, res ){
      console.log('match');
      res.end('Authorized ja');
  }
);

You can see that after we authenticate user, we proceed to the function(req,res){ block. In this block, we have to query information for user again which is redundant work. We can avoid this by using Passport custom callback as below

//passport custom callback
server.post('/auth',
  function(req, res, next) {
    passport.authenticate('basic', function (err, user, info) {
      if (err) {
        return next(err);
      }
      if (!user) {
        res.send({ status:"error" , message: 'Incorrect username/password'});
        return res.end();
      }
      res.send(user);
      res.end();

    })(req, res, next);
  }
);
passport.use(new BasicStrategy(
  function(username, password, done) {

    userService.login(username,password, function(err, user, info){
      return done(null, user);
    });
  }
));

With this, we can authenticate user and return the result to respond at the same time. However, this might not be your desired behavior for Passport Strategy because it’s against Single responsibility principle.

In the end, it’s up to you to decide which one suits you most. Until next time!

Node.js learning progress 3 - Restify and Passport(Basic)

I’m embarrassed to admit this but I’ve spent many hours to make this work

I’m still with node.js but not Dr.Dave this time. I’m working with my friend on a new idea of mobile application and I’m responsible for backend side.

My friend let me choose backend technology and obviously I chose Node.js (just for learning purpose). Anyways, since this is a mobile app, I don’t really care much about view rendering so screw jade and ejs! I searched for Node REST API stuff and ended up with restify. The author claims that it’s just like express but more focus on web service which is exactly what I want.

I’m happy with restify so far until I start working on authorization part. I pick up passport.js as a package of choice and ues Bsic Strategy which implement Basic Auth. Its reputation is great so why not?

I follow guides/tutorial both for restify and express but it does not seem to work. I cannot explain what’s the problem but it just not work. I’ve tried many alternative routing until I get it to work with the following

//server.js
var server = restify.createServer();

server.use(restify.bodyParser());
server.use(passport.initialize());

server.get('/users',
  passport.authenticate('basic',{ session: false}),
  function( req, res ){
      console.log('match');
      res.end('Authorized ja');
  }
);

Make sure you’ve require passport and passport-http first. You can define your strategy on the server.js or in a new file, whatever suit you but I prefer having authentication logic in its own file so I have auth.js and require it in server.js Here’s my auth.js

//auth.js
var passport = require('passport');
var BasicStrategy = require('passport-http').BasicStrategy;
var user = require('./user.js');

passport.use(new BasicStrategy(
  function(username, password, done) {;
    if (username.valueOf() === 'validusername' &&
      password.valueOf() === 'validpassword')
      return done(null, true);
    else
      return done(null, false);
  }
));

I actually wish I could move passport.authenticate to auth.js, export it and just call ‘auth.authenticate’ or something but I cannot and I don’t know why T_T If anybody can tell me how to do it please do so. (But I don’t have comment section here, hmm..)

Node.js learning progress 2 - Express

Here comes the polar express

As I mentioned in my previous post, I’m learning to write a Node.js web application using MEAN stack now.

Whereas it seems like MEAN.js provides all we want in single package, I prefer to learn a framework one by one. Also, from GitHub repository, if I want to use MEAN I’ll need to use bower and grunt which I’m not familiar with. So, I’ll just start with a simple Express.

Express can be installed using

$ npm install express --save

the –save command means that we want to add express to dependency list in package.json. There also is a express-generator which act like a scaffolding/skeleton helper to make it easier to create an app structure. You can follow the guide here.

From what I see, express is pretty simple and minimal, the only thing that I feel like I need to think is how should we route incoming requests. The site provide us several ways of doing that. Though, sometimes it means more problems to have many options. However, since my app is pretty simple (about 5 pages), I’ll go with the simplest one. In the future, I might try the Namespace routing

Here’s how my directories looks like now.

Structure

Admittedly, this is not the best structure. Later I might consider creating a new directory and put views, model, service directories there but I’ll just leave them like this for now.

You can see the demo here. It’s not working yet, still need to implement Angular.js. and since Angular is on the edge of change, I’m considering waiting for Angular 2.0.

Next thing I want to have a look is Mongoose. Perhaps I’ll use it to store chord progressions for dictionary page.

Node.js pitfall #1

  1. For loop does not work the way you expect.

Node.js learning progress 1 - Basic stuff + Locomotive

Merry Christmas!

Lately I’ve been busy with learning Node.js and javascript stuff. So I think it might be a good idea to share the progress of my learning.

I’ve been working with Java as a Web App developer since I graduated. So, when I step into Node.js world I tend to follow the same old project structure of Java. I first tried to search for an MVC framework which I end up with locomotive which is based on Express.

I like to learn by experience so I create a website called SongAnalyzer for this project. The web site is really simple. It has only 2 features. The first one is Keyfinder. The site will take chords as input and try to analyze it and return the most compatible key of those chords. The second one is Analyze Chord Progression. It also takes chords as input but this time it will try to analyze the chord progression and see if it’s one of the common chord progressions or not.

In order to analyze chord progression, we have to know the key first which we can retrieve by using our own keyfinder. The second thing to decide is how should we store common chord progression data. Since I’m very new to Node.js and never had an experience with MongoDB/Mongoose, I choose to store chord progression in a properties file using this module. Once the program read the properties file, it will create a tree and keep that tree in memory. Then we do travese and split chords in to progression..

You can see the demo here. It’s on heroku.

Now that I gain some knowledge and basic stuff of Node.js. Next thing I wanna do is to improve this site. However, while I was working on locomotive, I somehow felt that this is not the way Node.js is supposed to be used. Node.js should not be used as a Servlet and render html. Instead, it should be used as web service that contain many services and expose those little services to frontend. If we’re going to make website using Node.js, it’s supposed to be full AJAX. Again, this is purely my opinion and I might be wrong. The concept of full AJAX seems to go well with MEAN.JS. This stack encourages me to decide that the next thing I gonna do is to ditch this locomotive and simply use Express + Angular instead!

Things I hate about Node.js so far

  1. Asynchronous. Asynchronous is good but there’re times that I wish there is another option. Some Node.js core such as readFile give us an option to choose asyn/syn but third-party sometimes does not provide such option.

กำลังหัดเขียน Node.js + javascript อยู่คับ

demo site
github repo
ใครสนใจมาหัดด้วยกันได้นะคับ

เจิมจ้า

ลาก่อน wordpress

ในที่สุดก็มีบล็อกแนว minimal ที่เค้าฮิตๆกันเป็นของตัวเองซะที :) บล็อกนี้ใช้ Jekyll (อ่านว่า จะกริ้ว~ รึเปล่า) เขียน จะกริ้วเค้าโฆษณาว่าเป็นตัว generate static site โดยพอเรา commit code ขึ้น github ไป มันจะเจนออกมาเป็นเว็บให้! (โอโห~) หลังจากลองเล่นๆดูแล้วคิดว่าตรงจุดกว่า wordpress ที่มันดูหนักๆไปนิดนึงสำหรับคนที่แค่จะเอามาบล็อก แต่ยังงง syntax ในการเขียน html มันอยู่ คงต้องลองเล่นๆไปก่อน

ปัญหาต่อไปคือ จะเขียนอะไรลงบล็อกดีวะเนี่ย ชีวิตก็ไม่ได้มีอะไรน่าสนใจเท่าไหร่ ฮ่าๆๆ