귀찮은 일은 다 맡겨라. Grunt Javascript task runner.


특정 디렉토리 안에서 파일이 수정되면 컴파일을 해야 하는 상황이 생겼다.
글자 하나 바꿀 때마다 일일이 그런 수고를 하려니 여간 귀찮은 일이 아니다.
이런 때는 보통 bash 쉘 스크립트를 써 왔는데, os관계없이 어디서나 작동하고, 간편한 녀석을 찾다가 grunt(http://gruntjs.com)를 만나게 되었다. grunt는 프론트엔드 계통에선 꽤 이름을 날리는 녀석으로, 초반 웹 환경 구축을 도와주는 Yeoman(http://yeoman.io)의 한 부분이기도 하다. 요즘엔 grunt와 비슷한 gulp(http://gulpjs.com)이 성능 면에서 우수해서 인기가 좋은데, 여러 작업을 연달아서 할 때 pipe를 이용해서 I/O에 들어가는 시간을 줄이기 때문이란다. 그러나 나는 지금 연속적인 작업에 쓸 것도 아니고, grunt에서도 조만간(?) pipe를 지원할 예정이라고 하니, 커뮤니티가 활성화된 grunt를 쓰기로 했다.

grunt 설치

npm i grunt-cli -g

grunt를 실행할 해당 폴더에서 로컬 모듈 인스톨( 예 : static 폴더에서 실행시 static 폴더에 가서 인스톨)

npm install can-compile --save-dev
npm install grunt-shell --save-dev
npm install grunt-contrib-watch --save-dev
npm install time-grunt --save-dev


grunt 설정파일 예제 - Gruntfile.js

module.exports = function (grunt) {
    var static_path = '../static';

    // Project configuration.
    require('time-grunt')(grunt);
    grunt.initConfig({
//        pkg: grunt.file.readJSON('./package.json'),

    shell: {
      scsscompile:{ // scss컴파일은 외부 파이썬 스크립트를 이용해서 한다. 그래서 grunt-shell이 필요하다.
        command: 'python2 ../css.py '+static_path,
        options: {
            stdout: true
        }
      }
    },
    cancompile: { // mustache파일을 하나의 자바스크립트 파일로 합쳐주는 모듈
        dist: {
            src: [static_path+'/views/**/*.mustache'],
            out: static_path+'/js/views.build.js',
            wrapper: 'define(["can/view/mustache"], function(can) { {{{content}}} });'
        }
    },
    watch: { // grunt watch를 실행하면 해당되는 파일 변경사항이 생길 때 마다 스크립트를 자동으로 실행 한다.
      run_mustache: {
        files: [static_path+'/views/**/*.mustache'],
        tasks: ['cancompile']
      },
      run_scss: {
            files: [static_path+'/scss/**/*.scss'],
            tasks: ['shell:scsscompile']
      },
        options: { nospawn: true, livereload: true } // watch 성능이 향상된다.
    }
  });

//   grunt.registerTask('default', ['watch']); 로 설정하면, 파라미터 없이 grunt를 실행할 때 watch를 실행한다.
  grunt.registerTask('watch', ['watch']);
  grunt.registerTask('mustache', ['cancompile']);
  grunt.registerTask('scss', ['shell:scsscompile']);
  grunt.registerTask('static', ['cancompile','shell:scsscompile']);

  grunt.loadNpmTasks('can-compile');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-contrib-watch');
};
이 간단한 설정 파일 하나로, 쓸만한 watcher가 만들어졌다. :D
앞으로도 귀찮은 작업을 떠넘길 때 종종 이용해야겠다.

문제 해결


npm이 sudo 권한 없이 설치되지 않을 때

http://stackoverflow.com/questions/16151018/npm-throws-error-without-sudo
sudo chown -R `whoami` ~/.npm
sudo chown -R `whoami` ~/node_modules
sudo chown -R `whoami` /usr/lib/node_modules


Grunt - Recursive process.nextTick detected. This will break in the next version of node. Please use setImmediate for recursive deferral. 에러가 발생할 때.

http://stackoverflow.com/questions/22285942/grunt-throw-recursive-process-nexttick-detected
grunt.registerTask('sass',['sass']); // 이런식으로 작업 이름과 등록 이름이 같을 때 문제가 발생한다.
grunt.registerTask('styles',['sass']); // 이런식으로 이름을 바꿔준다.

유용한 링크

http://gruntjs.com/
http://gulpjs.com
http://jaysoo.ca/2014/01/27/gruntjs-vs-gulpjs/
http://yeoman.io/blog/performance-optimization.html



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

애증의 사바용. Sabayon Linux.

주 OS를 리눅스로 바꾼 뒤로 Arch리눅스 기반의 Manjaro를 쭉 써왔다.
그러다 반년 전 랩탑을 바꾸면서 새로운 리눅스 배포판을 사용해 보기로 했는데,
바로 Gentoo기반의 Sabayon 리눅스다.
젠투의 장점이라면, 내가 원하지 않는 쓰잘데 없는 패키지를 설치하지 않고 딱 원하는 것만 설치할 수 있다는 것이다.
그래서 때때로 아주 기본적인 기본을 동작시키는데도 어마어마한 노력이 들어가기도 한다.
오 년 전쯤 주 OS를 리눅스로 바꿔보겠다며 일주일 동안 젠투와 씨름하다가 그래픽카드 드라이버를 못 잡고 좌절했던 기억이 떠오른다.
‘그래. 그땐 그랬지. 하지만 시대는 많이 변했으니까.’
설치하기도 편리한 젠투 기반의 배포판 사바용.
아무런 문제도 없이 설치되었고, 쓰는데도 무리가 없었다.
그런데 어느 날 갑자기 알 수 없는 오류를 내며 부팅이 되지 않았다.
빌어먹을.
‘이 기회에 다른 리눅스로 바꿔 타?’
다른 여러 배포판을 설치해 보려고 낑낑거렸지만, 대부분 리눅스 배포판에서 UEFI를 제대로 지원하지 않았다.
빌어먹을.
울며 겨자 먹기로 다시 애증의 Sabayon 리눅스를 설치했다.
이걸 쓰면서 여러 문제와 맞딱뜨린다.
버츄얼박스를 켜면 컴퓨터가 다운되질 않나….
그래도 다른 걸 새로 깔 엄두가 나지 않아서 계속 썼는데,
이번에 아주 큰 문제가 발생했다.
WIFI를 못잡는거다.
랩톱인데 무선 인터넷을 못 잡으면 끝이다.
WIFI를 잡아보려고 여러 글을 읽어보고 수많은 시도를 해봤지만, WIFI는 결코 동작하지 않았다.
신호를 못 잡는 건 아니고, 신호가 잡혀서 연결을 시도하면, 연결되지 않는 문제인데 다른 기기에선 잘 잡히는 무선 인터넷이 유독 랩톱에서만 안 잡힌다.
망할.
일주일도 넘게 와이파이랑 씨름하다가 느꼈다.
‘내가 왜 와이파이 하나 잡는데 일주일을 보내야 해?’
누군가 젠투를 사용한다면 리눅스 전문가이거나, 사디스트가 분명하다.
설령 지금은 그 둘 중 하나가 아니더라도 계속 쓰면 그렇게 될 수밖에 없겠다.
어쨌거나 나는 그 둘 중 하나가 되기 전에 젠투 기반의 Sabayon을 떠나기로 마음먹었다.
무선 인터넷 잡자고 일주일을 더 보내긴 싫으니까. 그렇다고 잡힌다는 보장도 없고.
안녕! 애증의 Sabayon.

아래는 그동안 Sabayon을 사용하며 적은 노트이다.

Sabayon 버전 정보

cat /etc/sabayon-release

커널 정보 보기

eselect kernel list

엔트로피 업데이트

equo update
equo upgrade
equo conf update

grub 설정

/etc/default/sabayon-grub

auto login

lightdm
/etc/lightdm/lightdm.conf
[SeatDefaults]
autologin-user = username
utologin-user-timeout =0

slim
/etc/conf.d/xdm
DISPLAYMANAGER="slim"
rc-update add xdm default
/etc/slim.conf
defaultuser yourusernamehere
auto_login yes

session 삭제

$HOME/.cache/sessions

VirtualBox 설치

http://wiki.sabayon.org/index.php?title=HOWTO:UsingVirtualbox
vboxdrv 오류시
modprobe -r vboxdrv
modprobe vboxdrv

Midori

http://wiki.xfce.org/midori/faq
~/.cache
export XDGCACHEHOME=/dev/shm

한글 입력

http://wiki.gentoo-kr.org/index.php?title=GentooKoreanEnv
폰트 설치해 준다.
Sabayon 10.8 mate버젼에서는 한글이 잘 안써져서 입력기를 따로 설치해야 했지만,
Sabayon 10.8 xfce버젼에서 ibus로 한글 잘 써진다.
Session and startup > Application Autostart에 ibus-daemon을 추가한다.
ibus-daemon -drx

영문키보드에서 한영키 사용

Setting -> Keyboard -> Layout
Keyboard model : Generic 105-key (Intl) PC (Generic중 아무거나 해도 되는듯)
Leyboard Layout : Korean / Korean (101/104 key compatible)
IBus Preferences -> Advanced -> Keyboard Layout에서 Use system keyboard layout에 체크한다.

CPU점유율 100%

테마 선택에 따라 CPU점유율에 차이를 보일 수 있다.
Equinox 테마를 사용했더니 자꾸 CPU 점유율 100이 되고 컴퓨터가 먹통이 된다.

OpelGL setting

sudo eselect opengl list
sudo eselect opengl set 1


xnview

xnview 구동을 위해선 libpng12를 설치해야 한다.

개발

java 설정

OpenJDK를 사용시 Intellij를 쓸 때 성능 저하가 일어나므로 Oracle Jdk Bin을 설치한다.
Oracle Jdk를 기본 vm으로 설정한다.
java-config --list-available-vms
java-config --set-system-vm=oracle-jdk-bin
env-update

Maria db 설치

  • mysql 삭제
  • maria db 설치
  • sudo mysqld_safe 실행
  • Fatal error: Can't open and lock privilege tables: Table 'mysql.host' doesn't exist 에러 발생
  • sudo /usr/share/mysql/scripts/mysqlinstalldb --basedir=/usr
  • sudo mysqld
  • /usr/bin/mysqlsecureinstallation
  • 완료
http://forums.gentoo.org/viewtopic-p-7333862.html
rc-update add mysql
rc-update del mysql


/etc/systemd/system/mysqld.service:
[Unit]
Description=MySQL Server
After=network.target


[Service]
ExecStart=/usr/bin/mysqld_safe --defaults-file=/etc/mysql/my.cnf --datadir=/var/lib/mysql --socket=/var/run/mysqld/mysqld.sock
User=mysql
Group=mysql
WorkingDirectory=/usr

[Install]
WantedBy=multi-user.target

sudo systemctl status mysqld.service
http://superuser.com/questions/384365/systemctl-enable-differs-from-systemctl-start-how

Sabayon 사용시 유용한 링크

http://wiki.sabayon.org/index.php?title=Howtooptimizeandaccelerateyoursystem
https://wiki.sabayon.org/index.php?title=HOWTO:UpgradekernelusingEntropy
https://wiki.sabayon.org/?title=HOWTO:UpgradekernelusingEntropy
https://wiki.sabayon.org/index.php?title=En:FAQ#HowDoIenableAutologin.3F
http://wiki.gentoo.org/wiki/Localization/HOWTO
http://www.gentoo.org/proj/en/perl/g-cpan.xml



by


Tags : , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

아마존 클라우드 AWS. 효율적인 설계를 위한 Architecting on AWS.


퍼블릭 클라우드 하면 Amazon, Google, Microsoft 이 세 회사가 떠오른다.
이 세 곳 중에 어느 클라우드가 좋을까 여러 글을 찾아보았다.
모두 장단점이 있지만, 결국 개발자 입장에서 제일 편한 AWS를 쓰기로 마음을 먹었다.
Microsoft의 azure는 말로는 다 쉽게 된다는데,
막상 실제로 하려면 참조 자료도 별로 없고 원하는 데로 되질 않는다.
구글 클라우드 플랫폼은 꽤 안정적으로 보이긴 하지만,
이미 너무 많은 구글 제품을 쓰고 있는 나는 좀 다른 걸 써 보고 싶었다.
사실 더 큰 이유는 구글 클라우드를 쓰기로 마음먹고 개발한 것이 아니므로
이대로 구글에 배포하면 구글에서 제공하는 좋은 자원을 제대로 활용하지 못하기 때문이다.
그래서 결정한 AWS.
좀 써보니 라이브러리도 잘 되어있고 마음에 든다.
그러나 글로만 배운 것은 한계가 있는 법.
춤을 직접 춰봐야 늘지 글로 배워봤자 얼마나 배우겠는가?
기술도 마찬가지로 직접 써봐야 익숙해지고 는다.
그래서 실습과 교육이 적절히 이루어진 Architecting on AWS교육을 듣게 되었다.
교육이 재미있고 지루할 틈 없이 지나가서 아주 만족스럽다.
분기별 한 번씩은 열릴 예정이라고 하니,
AWS에 관심을 가진 사람은 한번 들어볼 만하다.

Architecting on AWS 메모와 팁


보안

설계

  • private subnet에서 밖으로 나갈 땐 Network address translation (NAT) 서버를 이용한다.
  • 서버에 바로 접속을 허용하지 말고, Bastion 서버를 통과해서만 접속이 가능하도록 한다.
  • EIP를 이용하는 것 보다 ELB를 이용하는편이 보안에 좋다.

권한

  • 마스터 유저는 사용하지 말고, IAM(Identity and Access Management)를 이용해 각각의 권한을 지닌 사용자를 만들어 쓴다.
  • 항상 권한을 가질 필요가 없다면, STS(Security Token Service)f를 이용해 사용자가 필요한 임시 권한을 주었다가 회수한다.
  • 유저는 Role을 가지거나 User Group에 속해서 권한을 가지는 경우가 있는데, STS를 통해 Role을 지닌 유저 키를 받아오면 보안에 더 좋다.

좋은 클라우드 설계를 위한 안티패턴과 패턴

안티패턴/ 패턴

  • 수동 프로세스 / 자동 프로세스
  • 밀결합(Thightly-coupled) / 소결합(Loosely-coupled)
  • 세션 사용(Stateful) / 세션 미사용 (Stateless)
  • 수직적 확장 / 수평적 확장

자동 구성 도구(Bootstrapping)

  • 스크립트 (Bash, 파워쉘)
  • 구성관리 도구(Chef, Puppet)
  • Amazon OpsWorks
  • http://169.254.169.254/latest/meta-data/

AWS 제품 소개 / 팁

네트워크

Router 53

서버 부하가 많이 걸리면 DNS(Router 53)에 Round-robin 설정 후,
동일 도메인 (예:dorajistyle.pe.kr)에 서브도메인(Record Type A)으로 각 서버의 ip를 설정한다.
www.dorajistyle.pe.kr은 CNAME타입으로 dorajistyle.pe.kr에 연결한다.
그러나 이 방법은 서버를 추가할 때마다 매번 설정을 변경해야 하는 불편함이 있다.
ELB를 사용하면 이런 불편함을 줄일 수 있다.
Router 53에는 Alias type이 있어서 value에 도메인을 넣으면 alias된다.
elb주소를 alias하려면 dorajistyle.pe.kr의 alias로 ELB주소를 붙인다.

ELB

ELB 참조 시, IP 어드레스를 절대로 사용하지 말고 A레코드를 항상 사용한다.

CloudFront

약정 할인 되고, 유일하게 네고가 가능한 서비스다.
월 10테라 이상이면 CloudFront가 S3보다 저렴하다.
정적(static) 컨텐츠 뿐 아니라 동적(dynamic) 컨텐츠도 캐쉬 가능하다.
그러나 동적 컨텐츠를 캐쉬하게 되면 비용적인 부담이 생길 수 있다.

스토리지

Amazon EBS

내구성이 필요하고 공유 가능한 스토리지를 원한다면 사용한다.

Amazon RDS

데이터베이스

DynamoDB

NoSQL 데이터베이스

S3

Eventually Consistent기 때문에 수정 결과가 바로 반영되지 않을 수 있다.
RRS(Reduced Redundancy Storage, RRS)
표준 스토리지보다 중복 수준을 낮추어 비용을 절감한다. 내구성 99.99%
S3는 Request당 과금하기 때문에, S3에 올리고, 그것을 가공해서 다시 S3에 올릴때도 비용이 발생한다.
한번의 Request에 여러 개의 파일을 묶어서 업로드가 가능하다.

배치

SNS

Http, Email, SMS, 모바일 푸쉬 등 여러 대상에 Push한다.

SQS

단순 큐.
큐에 있는 것을 처리하는 EC2서버는 ELB에 물려 있을 필요가 없다.
EC2서버가 항상 SQS 큐를 바라보기 때문에 큐 자체가 ELB역할을 하기 때문이다.

SWF

여러가지 작업을 실행할 때 여러개의 큐를 생성할 필요 없는 여러 작업의 워크플로우(BUS)
순차적으로 이루어져야 하는 경우에 유리하다.

CloudFormation

현재 구성을 JSON형식으로 정의한다.
다른 환경에서 같은 환경을 구축하려고 할 때 유용하다.

CloudInit

EC2 인스턴스를 생성할 때 userdata에 스크립트를 넣으면 첫번째 부팅시 사용자 데이터를 스크립트로 인식하여 실행한다.
#!(리눅스)
<script> (윈도우)

AMI

Ami에서 aws cli로 s3에서 원하는 부분 복사가 가능하다.

관리

CloudWatch

Metric 측정 도구이다.
5분 단위로 측정은 무료, 1분 단위로 측정하면 인스턴스당 $3.5
커스텀 측정치는 측정치당 월 $0.50

CloudWatch

지정된 범위가 침해되면, 경보를 발생하여 지정된 액션을 실행한다.
* SMS 통지
* 이메일 전송
* AutoScaling
* 인스턴스 정지
5분 주기면 무료이고, 1분 주기로 체크하면 과금이 된다.

Auto Scaling

보일러 온도 조절기를 생각하면 편하다.

desired capacity : 초기에 띄울 인스턴스 갯수
min : 최소 인스턴스 갯수
max : 최대 인스턴스 갯수
AZ-a,b : 어느 존에 인스턴스를 띄을 것인가? (desired capacity/AZ 해서 각 AZ에 인스턴스를 띄워준다.)
서버 갯수가 고정인 경우라도 Auto Scaling을 쓰면 안정성이 향상된다.
(예 : desired capacity = 1 max = 1 AZ-a,b)
어플리케이션 서버에 문제가 생기면 자동으로 새로 띄워준다.
AZ에 문제 발생시 문제가 없는 AZ에 인스턴스를 띄워준다.
사람이 직접 실행하거나, CloudWatch알람을 걸어서 자동으로 실행할 수 있다.

예)
인스턴스가 가동하기까지 준비시간이 필요하므로, 스케일 아웃은 미리 하고, 스케일 인은 보수적으로 한다.
인스턴스가 생성되면 기본 한시간 비용은 나오기 때문에, 스케일 아웃과 스케일 인이 너무 빈번하게 일어나면 좋지 않다.
트리거: CPULoad
측정치 (M) : 평균 CPU사용량
5분간 M > 80% 이면 스케일 아웃
20분간 M < 40% 이면 스케일 인

오토 스케일링 시나리오

Service - EC2 선택
ELB 생성 TCP프로토콜 + 80 포트, Health Check Interval은 적절한 값(예: 0.1)으로 설정한다.
Launch Configuration 생성
Security Group에 HTPP Rule을 추가한다.
Auto Scailing Group 생성
서브넷은 1개 이상 추가한다.
설정에서 Receive traffic from Elastic Load Balancer(s)에서 로드 발란서를 선택한다.
Keep this group at its initial size에 체크하고 생성한다.
인스턴스에 우클릭해서 오토 스케일링으로 생성된 인스턴스에 태그 부여.
설정 버튼에서 aws:autoscaling:groupName을 선택한다.
SNS토픽을 생성 한다.
E-mail Subscription을 생성한다.
Auto Scaling 연동 설정한다.
CloudWatch로 CPU Alert 생성한다.
Create Alarm > AutoScaling 검색 > CPUUtilization
Define Alarm Threshold 를 잘 설정한다.
(예) 부하가 50이상일 때 >= 50)
Auto Scaling Policy를 생성 생성한다.
해당 알림에 따라 실행할 동작 지정한다.

비용

네트웍 비용은 나가는 것을 기준으로 한다.
On-demand instances 소매가
Reserved instances 약정할인 (선납금을 조금 내고 조금 할인 받거나, 많이 내고 많이 할인 받는다.
Spot instances 남는 인스턴스를 경매 방식으로 구입해서 사용한다. (가격변동이 있다.) 경매에 지면 자동으로 꺼진다.
일반적인 백그라운드 프로세싱에 사용한다.
하나의 ELB에 여러개의 ASG(Autoscaling Group)을 붙일 수 있다. 예를 들면 하나는 온디멘드, 다른 하나는 스팟 인스턴스 그룹으로 만들어 두면 하이브리드 구성이 가능하다.

링크

아키텍팅

http://aws.amazon.com/ko/architecture/
http://prezi.com/cxpwi_og7lht/aws-regions-and-availability-zones/
http://translate.google.com/translate?hl=ko&sl=ja&tl=ko&u=http%3A%2F%2Faws.clouddesignpattern.org%2Findex.php%2F%E3%83%A1%E3%82%A4%E3%83%B3%E3%83%9A%E3%83%BC%E3%82%B8

보안

http://blogs.aws.amazon.com/security

AWS Elastic Beanstalk

http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts.platforms.html
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/createdeployPythoncustomcontainer.html
http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/customize-containers.html

최적의 비용 계산기(기술지원 신청하면 사용 가능)

http://aws.amazon.com/support/trustedadvisor



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

똑똑한 웹사이트 성능 테스트. sitespeed.io


웹 사이트 성능을 테스트해주는 곳은 많다.
온라인에서 사이트 성능을 측정해주는 핑돔(http://tools.pingdom.com/fpt/) 같은 서비스도 있고,
크롬을 주로 쓰는 개발자라면 크롬 개발자 도구에 Pagespeed(https://developers.google.com/speed/pagespeed/)을 깔아 쓰는 방법도 있다.

sitespeed.io(http://www.sitespeed.io/)는 우연히 찾아낸 웹사이트 성능 테스트 도구인데,
이걸 보고 웃음이 절로 나왔다.
스머프처럼 랄랄라랄랄라 노래를 흥얼거리고 깡총 거리면서 걷게 되었다.

나를 기분 좋게 한 sitespeed.io의 특징

  • 여러 페이지를 한 번에 테스트할 수 있다.
  • 다양한 뷰포트를 지원한다.
  • 유저 에이전트를 직접 지정해도 된다.
  • 결과를 html 페이지로 깔끔하게 보여준다.
  • 덤으로 페이지별 스크린 샷도 찍어 준다.
'아! 정말 아름다운 테스트 도구다!'
라는 감탄이 절로 나왔다.
그러나 기대가 크면 좌절도 큰 법.
내가 원하는 용도로 쓰려면 기능이 부족했다.

아쉬운 점 두 가지.

  • RESTful 사이트를 지원하지 않는다.
  • 테스트에 쿠키 정보를 넘기지 못한다.
이 두 가지가 되지 않는다면, 이 도구는 내게 아무 쓸모가 없다.
보기만 좋지, 제대로 된 능력을 발휘하지 못하는 것이다.
마치 사막에 버려진 고래처럼...

다행인 점은 sitespeed.io(http://www.sitespeed.io/)가 오픈소스라는 점이다.
그래서 나는 이 녀석과 불금을 보내고, 주말까지 함께했다.
덕분에 RESTful테스트는 해결되었고, 쿠키부분은 몇 부분 더 손 봐야 하지만,
곧 두 가지를 보완한 정식 버전이 나올 예정이다.

혹시 정식 버전이 나오기 전에 써보고 싶다면 아래 두 저장소를 clone 받아 사용하면 된다.
* https://github.com/dorajistyle/yslow
* https://github.com/dorajistyle/sitespeed.io

yslow를 컴파일해서 sitespeed.io/dependencies/yslow-3.1.5-sitespeed.js로 붙여넣으면 테스트가 가능하다.

yslow 컴파일 방법

sudo make phantomjs

curl 쿠키 저장 (여기서 나오는 쿠키 정보를 텍스트로 넣어주면 된다.)

curl -c sitespeed.io/cookie -X POST -H "Content-Type:application/x-www-form-urlencoded;charset=UTF-8" -d 'loginEmail=admin@dorajistyle.pe.kr&loginPassword=password' http://dorajistyle.url/authentications

yslow 쿠키 테스트(yslow 폴더에서 실행)

phantomjs ./build/phantomjs/yslow.js --info basic --format plain 'http://dorajistyle.url/admin' -C '{"name":"session","value":"sessionvaluestring","domain":"localhost"}'

screenshot 쿠키 테스트 (sitespeed-result 폴더에 저장됨)

phantomjs --ignore-ssl-errors=yes sitespeed.io/dependencies/screenshot.js 'http://localhost/#!test/page' sitespeed.io/sitespeed-result/screenshots/screenshot.png 1280 800 'Mozilla/5.0 (Macintosh; Intel Mac OS X 1084) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36' true '{"name":"session","value":"sessionvaluestring","domain":"localhost"}'

로그를 포함한 sitespeed.io 쿠키 테스트 (sitespeed.io 폴더에서 실행)

sh -x ./bin/sitespeed.io -f batchlist -k true -p 10 -C '{"name":"session","value":"sessionvalue_string","domain":"localhost"}'



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

joinedload를 사용한 SQLAlchemy 쿼리 최적화


SQLAlchemy는 파이썬(Python)용 Object Relational Mapper다.
ORM(Object Relational Mapper)은 객체(Object)와 관계형 데이터베이스(RDB - Relational Database)의 데이터 타입을 연결해 주는데,
이게 나오기 전엔 개발을 어떻게 했었나 싶을 정도로 아주 편리하다.

사용법도 간단해서 짧은 코드로 쿼리를 날리면 모델 하나를 딱 불러온다.
Model.get(model_id)
정말 좋다.
아무런 문제가 없었다.
적어도 외부 DB를 사용해 시험해 보기 전엔 그랬다.
외부 DB는 요청을 보내고 받는 시간이 길다.
헌데 SQLALCHEMY에서 자동으로 만들어 주는 쿼리를 쓰면, 너무 많은 요청을 보내게 된다.
그렇다면 성능을 향상하기 위해선?
요청 수를 줄이면 된다.

예제 모델-'SQLAlchemy Query Optimization. 쿼리 최적화'

예제의 product테이블은 여러 테이블과 연결되어 있는데,
쿼리를 날려 product와 관련된 테이블의 정보를 모두 불러와야 한다.
Sqlalchemy의 기본 쿼리 설정은 select로 연관된 table을 독립된 SELECT쿼리로 호출하지만,
응답시간이 느린 외부 DB를 쓴다면, 이를 join해서 쿼리 개수를 줄이면 된다.

sqlalchemy에서 join은 어떻게 하는가?

모델을 생성할 때 lazy='joined'를 써서 관련 테이블을 부를 때 join하는 방법과,
joinedload를 이용한 join 방법이 있다.
모델 생성 시 lazy를 사용해 join한 경우, 모델 호출 시마다 join이 되므로,
예제에선 필요한 상황에만 쿼리를 join하는, joinedload를 사용했다.

joinedload 간략 사용 방법

Model.query.options(db.joinedload(Model.relatedModel).all()

SQLAlchemy 쿼리 최적화 방법

  • 1..1 관계는 innerjoin한다.
    db.joinedload(Seller, innerjoin=True)
  • 1..n 관계는 innerjoin하지 않는다.
    db.joinedload(Tags)
  • 1..n 관계에서 관계가 깊다면, subqueryload를 써서 관련 테이블을 불러오고,
    그에 대해 joinedload를 해준다.
    db.subqueryload(Colors),
    db.joinedload(Colors, Inventory)
SQLAlchemy Query Optimization. 쿼리 최적화

위 방법을 써서 Call 개수를 25% 줄였다.
보통 Call이 29~30개가 나오다가, 22로 줄었으니, 약 7.5개 준 것이다.
Call당 시간이 얼마나 걸리냐에 따라 시간 단축이 가능한데,
테스트 환경에서 0.08초 정도 걸렸으므로 약 0.6초(0.08 * 7.5) 의 시간을 단축했다.
이건 데이터베이스의 응답 지연이 얼마나 되느냐에 따라 더 큰 차이를 보인다.
물론 로컬 db에서는 percall시간이 아주 짧으므로(테스트 환경에선 0.001초) 이런 최적화 차이를 체감하지 못한다.

참조

http://docs.sqlalchemy.org/en/rel09/orm/relationships.html
http://docs.sqlalchemy.org/en/rel09/orm/loading.html
http://stackoverflow.com/questions/6935809/how-to-use-joinedload-contains-eager-for-query-enabled-relationships-lazy-dyna
http://invenio-software.org/wiki/Tools/SQLAlchemy/Performance



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

서버에 부하가 얼마나 걸리나? Jmeter Http 부하(Load) 테스트.



여러 테스트 도구 중 Apache Jmeter를 선택한 이유.

  • 오픈소스.
  • 간편함.
  • 결과를 직관적으로 보여줌.
  • 사용자가 많음.
  • 문서 잘 된 편임.

Jmeter Http 부하 테스트 작성 순서

  1. Jmeter를 내려받는다. (http://jmeter.apache.org/download_jmeter.cgi)
  2. 압축을 풀고 Jmeter를 실행한다.
  3. Test Plan에 자식 노드 Thread Group를 추가한다.
  4. Therad Grup에서 Properties에 원하는 값을 넣어준다.
    Number of Thread는 테스트할 사용자의 수이고,
    Ramp-Up Period는 테스트를 몇 초에 걸쳐서 실행할 것인지 기간을 말한다.
    만약 Number of Thread가 10이고, Ramp-Up Period가 100이라면 각각의 Thread가 10초마다(100/10) 시작된다.
    하나의 Thread가 실행되고 10초의 여유 시간을 가지고 다음 Thread를 실행하는 것이다.
    Loop count에는 이 Thread를 몇 번 반복할지 적어준다.
  5. *만약 요청(Request)에 헤더 값을 설정해 줘야 한다면, Thread Group에 자식노드 HTTP Header Manager를 추가한다.
    Name과 Value값을 넣어주면 설정이 완료된다.
    예를 들자면 Name란에 Content-Type, Value란에 application/json을 적어주면 Content-Type이 application/json으로 설정된다.
  6. Thread Group에 자식 노드 HTTP Request를 추가한다.
  7. HTTP Request의 Web Server 란에 서버 이름(혹은 IP)와 포트 번호를 설정 한다.
  8. HTTP Request의 Path에 요청을 보낼 경로를 적어준다. (예: /about/company.html)
  9. HTTP Request의 Method를 Get으로 설정한다.
  10. HTTP Request에 자식 노드 Listener를 추가한다.
    여러 종류의 Listener가 있는데, View Results Tree는 각각의 요청에 대한 응답 결과를 보여주고,
    Summary Report는 종합적인 테스트 결과를 테이블로 보여준다.
    그리고 Spline Visualizer는 종합 결과를 그래프로 보여준다.
  11. *만약 여러 Thread Group에 대한 종합 결과를 보고 싶다면, Test Plan에 자식 노드로 Listener를 추가하면 된다.

아래는 예시를 위해 Jmeter로 테스트한 Spline Visualizer 결과값이다.

Flask 개발용 서버-'Jmeter로 Http 부하 테스트하기'
Flask 개발용(dev) 서버.

twisted-'Jmeter로 Http 부하 테스트하기'
twisted

twisted + Nginx -'Jmeter로 Http 부하 테스트하기'
twisted + Nginx

gunicorn + Nginx -'Jmeter로 Http 부하 테스트하기'
gunicorn + Nginx

각 테스트의 Summary Report를 정리한 표.-'Jmeter로 Http 부하 테스트하기'
각 테스트의 Summary Report를 정리한 표.

배포하기 전에 어떤 조합 성능이 좋을지 궁금하다면,
Jmeter를 이용해 각각 환경을 간단히 시험해 보면 좋다.

참고 자료



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

구글 블로거에서 블로그 글 목차 보여주기.

블로그를 시작한 지 어느덧 팔 년.
그동안 1,000개가 넘는 글을 썼습니다.
글이 많아지니 전에 썼던 글을 찾을 때, 한참 헤매는 경우가 많아요.
그래서 얼마 전 월풍서가라는 메뉴를 만들었습니다.
블로그에 썼던 글을 좀 편하게 찾아보려는 의도에서였지요.
레이블(태그)별로 RSS를 받아와서 자동으로 목차를 만들어 주면 좋겠다고 생각했는데,
구글 블로거엔 레이블 간 계층을 지원하지 않아 제가 원하는 목차를 만들기 어려울 듯 했습니다.
그래서 수동으로 정리를 시작했어요.
읽었던 책에 대한 글을 한참을 걸려 정리하고 나니, 다른 글을 정리할 엄두가 나지 않았습니다.
글을 새로 쓸 때마다 목차를 갱신해야 한다는 점도 큰 부담이었어요.
거의 반년 동안 목차 페이지를 반쪽짜리로 남겨두었더니 자꾸만 눈에 밟힙니다.
좀 제대로 된 목차를 만들어 보고 싶었어요.

그러던 중 아주 좋은 정보를 얻었습니다.

http://www.dorajistyle.pe.kr/feeds/posts/summary/-/A/B/C
식으로 피드를 받아오면 A,B,C 레이블을 모두 포함한 포스트 정보를 얻을 수 있다는 것이죠.
이거다 싶어서 코드를 짜다 보니 한가지 문제가 있습니다.
너무 많은 요청(Request)를 보내야 하는 것인데요.
결국 1차 레이블만 요청해서 받아온 결과를 클라이언트 단에서 처리해주는 방식으로 코드를 작성했습니다.
페이지를 읽는데 시간이 조금 걸리긴 하지만, 이정도면 만족스럽습니다.

월풍서가(月風書架)


목차를 만들며 레이블 정리를 새로 했습니다.
그러다 보니 예전 글을 좀 읽게 되었는데요.
정말 유치한 글도 보이고, 지금 봐도 마음에 드는 글도 있습니다.
나중엔 마음에 드는 글 목록도 만들어서 월풍서가에 넣고 싶어요.
이번에 글을 정리하다가 알게 된 한가지 사실에 충격을 받았습니다.
제가 미국의 문화식민이었다는 건데요.
블로그에 쓴 영화 감상평을 보면 미국 영화가 대다수더라고요.
한국을 포함한 다른 나라 영화를 모두 합쳐야 미국 영화를 본 수에 겨우 미칩니다.
저도 모르는 사이에 미국 문화에 크게 노출되어있던 거죠.
물론 앞으로도 미국 영화를 볼 때가 많겠지만,
미국 영화라는 것을 의식하고 보고,
다른 나라 영화도 두루 보아야겠습니다.

혹시 구글 블로거에 목차 페이지를 만들고 싶으신 분을 위해 코드를 공유합니다.
필요하신 분은 가져다 쓰세요.

구글 블로거에 목차 페이지를 생성해 주는 스크립트



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

크롬 개발자들이 들려주는 개발 노하우. Chrome developer day.

오랜만에 오프라인 강연을 들었습니다.
Chrome developer day.
평소 사용하는 Devtool 활용법과 PageSpeed 세션을 들으려고 갔어요.
PageSpeed는 뭔가 새로운 팁을 듣고 싶었는데 일반적인 이야기뿐이라 좀 아쉬웠습니다.
그래도 원래 들으려던 강연 말고도 전체적으로 만족스러웠어요.
특히 렌더링 관련 강연이 좋았습니다.
또 이런 좋은 행사가 열리면 찾아들어야겠어요.:D


신기술

flex-direction과 Position: sticky등 CSS와
Geolocation, Orientation등 자바스크립트 기능을 소개했다.
가장 눈에 띄었던 건 Offline events인데 네트워크에 연결되지 않은 상태라면 웹사이트에서 이를 인식한다. 이걸 이용하면 오프라인시에 웹에서 안내를 제공하면 되겠다.
localSotrage, Websql, indexdb 세 종류의 storage API도 소개했다.
semantic input types는 사용성 향상에 도움을 준다.
성능 측정이 필요하면 navigation timing API나 Resource timing API를 쓰면 된다.
그 밖에도 Camera, Web audio, getuserMedia, Web rtc(real time communication), webGL, android intend (QR) 등도 간략히 소개했다.


Polymer 라이브러리.

Web components.
DOM 엘리멘트로 되어있어 친숙하다.
그러나 템플릿 코드와 혼재하여 사용하면 코드가 지저분해지겠다.


DevTools

workspace를 이용하면 페이지 새로 고침을 하지 않고 실시간으로 확인할 수 있다.
workspace를 사용하려면 resource에서 원하는 파일을 add to workspace로 추가 해 주어야 한다.
sass와 less도 지원한다.

모바일 웹 환경에서 리모트 디버깅(https://developers.google.com/chrome-developer-tools/docs/remote-debugging)을 사용하면 편리하다.

타임라인(https://developers.google.com/chrome-developer-tools/docs/timeline)

  • 파랑은 로딩(Loading)
  • 노랑은 스크립팅(Scripting)
  • 보라색은 렌더링(Rendering - Recalculate Style)
  • 녹색은 그리기(Paint)

적절한 타임라인 순서 예시

  • Function Call
  • Recalculate Style
  • Layout
  • Paint Setup
  • Paint
  • Composite Layers

DevTools 페이지에 들어갔다가 테마를 입맛에 맞게 바꾸는 법을 발견해서 취향대로 바꿨다.
zerodarkmatrix(https://github.com/mauricecruz/chrome-devtools-zerodarkmatrix-theme)테마 참 잘 만들었다. 테마는 아래 폴더에 넣으면 된다.
Chromium: ~/.config/chromium/Default/User\ StyleSheets/

Html5 Games

Canvas, WebGL(OpenGL ES 2.0)(2007년에 나왔는데 IE11에서 이를 지원한다.), WebAudio, Fullscreen API, Pointer lock API, Web Workers, PNaCl(Portable Native Client) 등의 라이브러리를 이용하여 게임을 개발하면 된다.


Chrome Apps

  • 오프라인에서 동작(Offline by default)
  • 클라우드 친화적(Cloud ready)
  • OS에 자연스럽게 통합(Natively Integrated)
  • 다양한 장치 지원(Multi device support)

하드웨어를 제어할 수 있다.
Phonegap(http://phonegap.com/)을 이용하면 크롬 앱을 안드로이드나 iso 플랫폼 앱으로 변환할 수 있다.


성능

  • Element를 모두 렌더링 하는 것은 아니고 보이는 것만 렌더링 한다.
  • 모바일에서 touch시에 클릭 이벤트는 300ms를 기다려야 하니 touch 이벤트 리스너를 사용하여 지연을 줄여준다. (Canjs에선 touchstart 이벤트를 사용하면 되겠다.)
  • 1초에 60프레임 보여주려면 최대 지연율이 16.67ms 이하여야 한다.
  • 에니메이션 함수에 setTimeout(function, 16.67)을 이용한다.(http://stackoverflow.com/questions/729921/settimeout-or-setinterval)
  • redirect 쓰지 말자. 외부 api를 쓸때 dns lookup이 여러번 일어나는데 dns prefetch를 이용하면 성능이 향상된다.
  • CSS animation에

    {
    -webkit-transform: translateZ(0);
    -moz-transform: translateZ(0);
    -ms-transform: translateZ(0);
    -o-transform: translateZ(0);
    transform: translateZ(0);
    }

    를 이용해 GPU 가속을 활성화한다. (이건 핵이다.)
  • 웹 페이지 성능을 알아보려면 Pagespeed extension을 이용한다.
  • ATF(http://whatis.techtarget.com/definition/above-the-fold) 컨텐츠가 처음 15kb안에 배달되야 한다.(https://developers.google.com/speed/docs/insights/PrioritizeVisibleContent)

배치를 바꿀 때 transform을 이용하는 게 좋다고 하나, 문서(http://blog.tumult.com/2013/02/28/transform-translate-vs-top-left/)를 찾아보니 transition을 사용하지 않는다면 top/left로 위치를 잡는 것이 더 빠르단다. 심지어 불투명한 요소만 포함하고 있다면 GPU 가속 핵을 사용하지 않는 것이 더 빠르다. 배터리 소모도 고려해야 하므로 핵을 쓸 땐 잘 생각해서 쓴다.


Dartlang(https://www.dartlang.org)

구조화된 웹 앱을 개발을 돕는 새로운 개발 언어.
이미지 처리에 강점을 보인다니, 혹 게임을 만들 일이 생기면 한번 써봐야겠다.



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

파이썬 Flask에서 RequireJS Optimizer를 이용한 static폴더 최적화.

자바스크립트MVC를 이용할 경우 자바스크립트와 뷰 템플릿때문에 static폴더가 무겁습니다.
파일의 공백을 모두 제거하여 용량을 줄이면 좀 가벼워 지지요.
허나 파일 공백을 없애면 가독성이 떨어집니다.
난감한 상황이 발생해요.
길이 1m짜리 한줄코드를 고치고 기능 추가하는건 어렵잖아요?
변경이 빈번하게 일어나는 static 폴더.
개발 편의와 성능 두마리 토끼를 잡을 좋은 수가 없을까요?
RequireJS를 이용해 자바스크립트를 관리하신다면 방법이 있습니다!

우선 노드JS(http://nodejs.org)를 설치합니다.

RequireJS Optimizer를 설치합니다.

npm install -g requirejs

3. r.js를 다운로드 받습니다.(http://requirejs.org/docs/release/2.1.8/r.js)

4. 예제에서 사용할 어플리케이션 디렉토리 구조는 다음과 같습니다.

/build
  - r.js
  - build.js
/application
  __init__.py
  /static
    /views
      template.ejs
    /js
      app.js
      /vendor
        jquery-1.10.1.min.js
        bootstrap.min

application/init.py

from flask import Flask
app = Flask(__name__)
# static 폴더 경로를 지정해 줍니다. debug일땐 ‘static’폴더로 경로를 설정하고 나머지는 ‘static-build’를 경로로 잡습니다.
app.static_folder = 'static-build'
if app.debug:
        app.static_folder = 'static'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

application/static/js/app.js

자바스크립트 어플리케이션 파일입니다.
requirejs의 기본 설정을 담고 있습니다.

require.config({
    "baseUrl": "/static/js",
    "paths": {
        "jquery": [
            "//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
            "vendor/jquery-1.10.1.min"
        ],
        "jquery.bootstrap": [
            "//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/js/bootstrap.min",
            "vendor/bootstrap.min"
        ],
    },
    shim: {
        "jquery.bootstrap": {
            deps: ["jquery"],
            exports: '$.fn.bootstrap'
        },
        enforceDefine: true
    }
});

requirejs(['jquery','jquery.bootstrap'],
    function ($) {
    // 어플리케이션 코드 
    }
);

/build/build.js

RequireJS용 build파일입니다.

{
    appDir: '../application/static',
    baseUrl: 'js/vendor',
    mainConfigFile: '../application/static/js/app.js',
    paths: {
        "jquery": "jquery-1.10.1.min",
        "jquery.bootstrap": "bootstrap.min",
    },
    dir: '../application/static-build',
    optimize: "uglify2",
    optimizeCss: "standard.keepLines",
    removeCombined: true, // combine된 파일은 남겨두지 않습니다.
    preserveLicenseComments: false,
    modules: [
        {
            name: '../app'
        }
    ]
}

프로젝트 루트 페이지에서 다음을 실행합니다.

JS/CSS파일을 최적화 하여 application/static-build 폴더에 저장합니다.
node ./build/r.js -o ./build/build.js

단 이는 js와 css만 최적화를 해 주기 때문에 Ejs 템플릿도 용량을 줄이려면 아래 커맨드를 이용하면 됩니다.
find ./application/static-build/views -name '*.ejs' -exec sed -i '/^\s∗\/\//d' {} \;
find ./application/static-build/views -name '*.ejs' -exec sed -i 's/^[ \t]*//g; s/[ \t]*$//g;' {} \;
find ./application/static-build/views -name '*.ejs' -exec sed -i ':a;N;$!ba;s/\n/ /g' {} \;

쉘 스크립트를 작성해 한번에 실행하면 간편합니다.

optimizer.sh

#!/bin/sh
cd './build'
node ./r.js -o build.js
cd '../application/static-build/views'
find . -name '*.ejs' -exec sed -i '/^\s∗\/\//d' {} \;
find . -name '*.ejs' -exec sed -i 's/^[ \t]*//g; s/[ \t]*$//g;' {} \;
find . -name '*.ejs' -exec sed -i ':a;N;$!ba;s/\n/ /g' {} \;

참고 자료



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Flask와 Canjs를 이용한 다국어 어플리케이션 토대

canjs와 python flask를 이용한 다국어 어플리케이션 제작을 위한 토대입니다.
Flask 부분은 Matt Wright님의 에서 영감을 얻었습니다.



Flask-Canjs-i18n-Boilerplate 소스



특징

  • Flask/Canjs 연동.
  • 다국어 지원.
  • 사용자 CRUD 구현.
  • 사용자 following/followers 기능 구현.
  • 소셜 네트워크 연결 구현.
  • 페이스북
  • 기타 (TODO)
  • RESTful API 구현.
  • 반응형 웹 디자인.
  • 구글 크롤러 친화적 url('#!').
  • 간편한 개발 문서 제작.(Sphinx)
  • 쉬운 테스팅. (nosetests)
  • 다양한 브라우저 호환 (IE7, IE8, IE9, IE10, Firefox, Chrome, Opera..)
  • 더 많은 기능을 윈하신다면, 함께 만들어 가요! :D


써보기

http://flask-canjs-i18n-boilerplate.ap01.aws.af.cm/



어떻게 동작하나요?

flask-canjs-i18n-boilerplate



환경


클라이언트 사이드

  • Canjs, 클라이언트 사이드 자바스크립트 프레임워크.
  • RequireJS, 자바스크립트 파일•모듈 로더.
  • Initializr, HTML5 템플릿.
  • Bootstrap, 프론트엔드 프레임워크.
  • Bootstrap-ie7, 부트스트랩 3에서 IE7을 지원을 도움.
  • mustache, 템플릿 엔진.
  • i18next, 자바스크립트 다국어 도구.
  • Font Awesome, 크기 변환등 개별화 가능한 백터 아이콘 모음을 제공.
  • typeahead.js, 텍스트 자동 완성 라이브러리.
  • spin.js, 작업중 활동 표시기.
  • Placeholders.js, 자바스크립트를 통해 HTML5의 placeholder 속성을 사용 할 수 있게 함.
  • Jade(pyjade), 파이썬용 Jade 템플릿 엔진 확장.
  • jQuery, 작고 빠르고 유용한 자바스크립트 라이브러리.
  • jQuery BBQ, HTML5 hashchange 이벤트 사용을 도와줌.

서버 사이드

  • Flask, 가벼운 파이썬 프레임워크.
  • Flask-Babel, 플라스크용 다국어 확장.
  • Flask-Gravatar, 플라스크용 그라바타 확장.
  • Flask-Security, 플라스크용 로그인 보안 확장.
  • Flask-Social, Flask-Security에서 Oauth를 지원하는 확장.
  • Flask-Assets, 자바스크립트와 스타일시트를 관리하는 플라스크용 확장.
  • Flask-SQLAlchemy, SQLAlchemy사용을 위한 플라스크용 확장.
  • Flask-WTF, WTForms 통합 확장.
  • Flask-Cache, 캐쉬 사용을 도와주는 플라스크용 확장.
  • Alembic, SQLAlchemy 데이터베이스 마이그레이션 관리 도구.
  • Celery, 분산 메시지 전달 기반의 비동기 작업 queue/job 큐.

디버깅과 테스팅

  • flask-debugtoolbar, django-debug-toolbar를 플라스크 용으로 포팅한 디버깅 툴바.
  • nose, 멋진 파이썬용 테스팅 도구.
  • BusterJS, 자바스크립트 테스팅 도구.

문서 생성

  • Sphinx, 지적이고 아름다운 문서를 만들어주는 도구.
  • JSDoc, 자바스크립트 문서화 도구.


설치


도구 설치

  • virtualenv, 분리된 파이썬 환경을 만들어줍니다.
  • virtualenvwrapper, virtualenv를 보다 편리하게 사용하도록 돕습니다.

프로젝트 복제

$ git clone https://github.com/dorajistyle/flask-canjs-i18n-boilerplate.git
$ cd flask-canjs-i18n-boilerplate.git

프로젝트를 위한 virtualenv 생성

$ mkvirtualenv flask-canjs-i18n-boilerplate

필요 라이브러리 설치

$ pip install -r requirements.txt

데이터베이스 마이그레이션

$ alembic revision --autogenerate -m "Alembic initilized boilerplate tables."
$ alembic upgrade head

관리자 추가

'admin@github.com'와 'password'로 로그인 하시면 됩니다.
$ python manage.py init_user

설정

설정 값을 올바르게 설정해야 합니다.(데이터베이스, 메일, 소셜 네트워크 정보...)

  • application/settings.py엔 서버 사이드 설정이 들어 있습니다.
  • application/frontend/static/js/settings.js엔 클라이언트 사이드 설정이 들어 있습니다.
  • ./alembic.ini엔 alembic설정이 들어있습니다.

번역

  • 서버 사이드 번역(Babel)은 applications/frontend/translations 폴더에 있습니다.
  • 클라이언트 사이드 번역(i18next)은 applications/frontend/static/locales 폴더에 있습니다.

바벨 번역 컴파일

$ python tr_compile.py



사용


어플리케이션 실행

$ python wsgi.py

어플리케이션 프로파일 실행

$ python profile.py

문서 생성

$ python generate_documents.py


정적 폴더 최적화

Nodejs 와 RequireJS가 설치되어 있어야 합니다.
더 자세한 문서를 원하신다면 다음을 클릭하세요. RequireJS Optimizer.
$ optimize_static.sh

테스트

$ nosetests

아래의 테스트 스크립트를 이용하셔도 됩니다.

$ python run_nosetests.py



사용권

Flask-canjs-i18n-boilerplate는 MIT license를 따릅니다.



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

파이썬 flask 개발 문서 만드는데 5분. Sphinx.

문서 작성도 개발의 일환입니다.
개발자는 깔끔한 문서를 만들고 싶지만,
문서 작성에 많은 시간을 들이고 싶지는 않지요.
Sphinx가 바로 그 딜레마를 해결해 주는 도구입니다.


Sphinx로 파이썬 Flask 개발 문서 만들기 순서

  1. Sphinx와 sphinxcontrib-httpdomain를 설치합니다.
    $ pip install sphinx
    $ pip sphinxcontrib-httpdomainproject 폴더에 doc 폴더 생성합니다.
  2. doc 폴더로 갑니다.
  3. sphinx-quickstart를 실행하여 기본 설정을 잡습니다.
    $ sphinx-quickstart
  4. conf.py에 다음을 추가합니다.
    sys.path.append(os.path.abspath('..'))
    # 확장
    extensions = ['sphinx.ext.autodoc',
    'sphinx.ext.intersphinx',
    'sphinxcontrib.autohttp.flask']
    # 테마 (default|basic|sphinxdoc|scrolls|agogo|traditional|nature|haiku|pyramid)
    html_theme = "nature"

    기본으로 제공하는 테마 외에도 내려받거나 직접 만든 테마도 사용 가능합니다.
  5. rst파일을 생성합니다.
    API 예시
    Users
    --------------------------
    .. autoflask:: application.api:create_app()
    :undoc-static:
    # api에 포함시키고 싶지 않은 blueprints.
    :undoc-blueprints:
  6. 문서를 생성합니다.
    $ make html

참고 자료

http://sphinx-doc.org/tutorial.html
http://sphinx-doc.org/theming.html
http://pythonhosted.org/sphinxcontrib-httpdomain/



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

개발이 끝났다면? NGINX서버와 supervisor를 써서 배포해 봅시다.

NGINX

/etc/nginx/nginx.conf
http {
keepalive_timeout 65;
gzip on;
add_header Cache-Control private;
gzip_static on;
gzip_http_version 1.1;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
gzip_vary on;
gzip_types application/x-javascript text/css *;

map $http_x_requested_with $nocache {
default 0;
XMLHttpRequest 1;
}

include /etc/nginx/sites-enabled/*;
}

/etc/nginx/sites-available/myapp.conf

server {
listen 80;
server_name _;

root /path/myapp;

access_log /path/myapp/logs/access.log;
error_log /path/myapp/logs/error.log;

proxy_cache_bypass $nocache;
proxy_no_cache $nocache;

location /static {
expires modified +24h;
alias /path/myapp/application/frontend/static-build;
}

location /api/_uploads {
expires modified +24h;
alias /path/myapp/images;
}

location / {
proxy_pass http://127.0.0.1:8000;
proxy_redirect off;

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_read_timeout 30;
}
}

* static 폴더를 설정할 때 주의 점
root를 사용할 땐 static 폴더의 상위 폴더를 지정하고,
alias를 사용할 땐 static폴더를 지정한다.

Upload file size setting
client_max_body_size

권한이 필요합니다. 오류 해결.
error log.
2013/07/10 18:31:54 [crit] 23626#0: *127 stat() "PATH" failed (13: Permission denied) request: "GET PATH HTTP/1.1", host: "localhost", referrer: "http://localhost/"
chmod 751 PATH
all path in PATH should have access permission.
PATH에 모든 경로에 접근 권한이 필요하다.
예) /home/example/applications/myapp 경로에 접근해야 할 땐.
/ , /home, /home/example, /home/example/application, /home/example/applications/myapp 에 접근 권한이 필요하다.

location 설정
인덱스 파일이 없을때 오류 처리와 디렉토리 목록을 보여준다.
autoindex on;

설정 파일 심볼릭 링크 걸기
ln -s /etc/nginx/sites-available/myapp.conf /etc/nginx/sites-enabled/

Arch Linux 기준 nginx 서버 실행과 정지.
sudo systemctl start nginx
sudo systemctl stop nginx


supervisor

/etc/supervisor.d/myapp.ini
[program:myapp]
command = gunicorn --debug --log-level debug -w 4 -b 127.0.0.1:8000 wsgi:application
; command = twistd web --port 5000 --wsgi wsgi.application
directory = /path/myapp
user = root
autostart=true
autorestart=true
; stdout_logfile=NONE
; stderr_logfile=NONE
; Handy for debugging:
stdout_logfile=/var/log/supervisor/webapp.stdout
stderr_logfile=/var/log/supervisor/webapp.stderr

supervisor 실행법
데몬 실행(테스트를 위해 프론트에서 실행함)
sudo supervisord -n
변경사항을 다시 읽고 업데이트 함.
sudo supervisorctl reread
sudo supervisorctl update
supervisor 실행
sudo supervisorctl start myapp
supervisor 재실행
supervisorctl restart webapp


※ 만약 고정 아이피에서 서비스를 한다면 gunicorn을 실행할 때 localhost가 아닌 고정 아이피 주소(예: gunicorn -b 123.456.789.000:8000)로 실행해야 외부에서 접근이 가능하다.
물론 nginx설정도 그에 맞게 변경해야 한다.

참고 자료



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

데이터베이스 마이그레이션 관리를 간편하게! alembic.

alembic은 파이썬 SQLAlchemy DB Toolkit과 연동하여 마이그레이션 관리를 돕는 편리한 도구입니다.

프로젝트 폴더로 가서 alembic을 초기화 한다.
alembic init alembic

alembic.ini파일에서 데이터 베이스를 설정해 준다.
sqlalchemy.url = mysql://scott:tiger@localhost/test

마이그레이션을 자동으로 생성하기 위해 다음을 alembic/env.py에 추가한다.
import os, sys
sys.path.append(os.getcwd())
from application import db
target_metadata = db.Model.metadata

* 자동 생성에서는 테이블명이나 컬럼명을 변경한 것은 감지하지 못한다.

다음 커멘드를 이용해 자동으로 마이그레이션을 생성한다.
alembic revision --autogenerate -m "Added account table"

DB를 새 마이그레이션으로 업그레이드 하려면?
alembic upgrade head

원하는 마이그레이션으로 업그레이드 하거나 다운그레이드 하려면?
$ alembic upgrade +2
$ alembic downgrade -1

alembic 튜토리얼



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Canjs와 Flask를 이용한 웹개발 예제

클라이언트 사이드 자바스크립트 프레임워크인 Canjs와
파이썬 마이크로 프레임워크인 Flask를 이용한 웹 어플리케이션 예제입니다.
이 Canjs + Flask 예제가 프레임워크 이해에 도움이 되길 바랍니다.


Canjs + Flask 예제 소스


예제에 사용된 라이브러리

  • Canjs, 클라이언트 사이드 자바스크립트 프레임워크.
  • RequireJS, 자바스크립트 파일•모듈 로더.
  • Initializr, HTML5 템플릿.
  • Bootstrap, 프론트엔드 프레임워크.
  • JSDoc, 자바스크립트 문서화 도구.
  • BusterJS, 자바스크립트 테스팅 도구.
  • mustache, 템플릿 엔진.
  • i18next, 자바스크립트 다국어 도구.
  • Flask, 가벼운 파이썬 프레임워크.
  • Flask-SQLAlchemy, SQLAlchemy의 플라스크 플러그인.
  • Jade(pyjade), 파이썬용 Jade 템플릿 엔진 플러그인.
  • Flask-Babel, 플라스크용 다국어 플러그인.

예제의 이해를 돕는 글



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

잘 짜여진 자바스크립트 MVC 프레임워크. Canjs

Backbone, AngularJS, Spine….
그동안 나왔던 자바스크립트 프레임워크를 조금씩 건드려는 보았지만,
항상 아쉬움이 남았습니다.
이번에 Canjs를 써보니, 정말 잘 만들어진 프레임워크라는 생각이 들어요.
자바스크립트MVC 프레임워크를 써 볼까 생각 중이시라면, Canjs 한번 고려해 보세요.

can.Control

컨트롤러에서 이벤트 처리

"li .destroy {Event.destroy}": function( el, event) {
var todo = el.closet('li').data('todo);
todo.destroy();
event.stopPropagation();}
});
Events = {destroy : "click"};

css Selector, html.getElementBy, $(selector)가 Control의 셀렉터로 사용된다.

When the element your Control is bound to is removed from the DOM,
the Control destroys itself, cleaning up any bound event handlers.

can.Control 이 아는 이벤트.
* change
* click
* contextmenu
* dblclick
* focusin
* focusout
* keydown
* keyup
* keypress
* mousedown
* mouseenter
* mouseleave
* mousemove
* mouseout
* mouseover
* mouseup
* reset
* resize
* scroll
* select
* submit

링크 처리 방법(How can I make a link in Canjs?)

레이어(layer)
<a id="id" href="javascript://">href</a>

페이지(page)
<a id="id" href="#!id">href</a>

무스타치에서 콜백 받기(Mustache Element Callback)

{{data 'model'}}

경로 설정(RequireJS Paths)

requireJS can require is /can
requireJS에서 canJS를 쓸 땐 can.js를 패스로 잡고 사용해야 한다.
registerHelper이용을 위해서는 can/view/mustache가 필요하다.

404루트 잡기(How to define a catch all route to handle 404 in can js?)

http://stackoverflow.com/questions/13824665/how-to-define-a-catch-all-route-to-handle-404-in-can-js

can.route.bind('change', function(ev, newVal) {
if (newVal === 'route') {
var valid = false;
$.each(can.route.routes, function(k,v) {
if (new RegExp(v.test).test(window.location.hash)){
valid = true;
return; //exit loop
}
})
if (!valid) {
//handle the false route here
}
}
});

다국어 지원(Localization)

Localization is a good example of a custom helper you might implement in your application. The below example takes a given key and returns the localized value using jQuery Globalize.

1. Mustache.registerHelper('l10n', function(str, options){
2. return Globalize != undefined
3. ? Globalize.localize(str)
4. : str;
5. });

can.route에서 i18next 데이터를 받아오지 못할 때

can.when을 이용하여 초기화가 된 후 can라우팅 처리를 해 준다.


var lang =utils.getParam('lang');
var i18noption = {debug: true};
lang != undefined
? i18n
option.lng = lang
: i18n_option.lng = "en";
can.when(i18n.init(i18n_option)).then(function (){});

모델 관계(model associations)

https://forum.javascriptmvc.com/topic/questions-about-model-associations

<div class="header">
<h1>Association</h1>
</div>
<!-- YOUR CODE HERE -->
<div id="contacts"></div>

can.fixture("/contacts.json", function(){
return [{
'id': 1,
'name' : 'Justin Meyer',
'birthday': '1982-10-20',
tasks : [{
id: 1,
title: "write up model layer",
due: "2010-10-5"
}]},{
'id': 2,
'name' : 'Brian Moschel',
'birthday': '1983-11-10',
tasks : [{
id: 2,
title: "write up funcunit",
due: "2009-5-1"
},{
id: 3,
title: "test funcunit",
due: "2010-3-15"}]
},{
'id': 3,
'name' : 'Bobby Joe',
'birthday': '1980-2-10'
}];
})

can.Model.convert.date = function(raw){
if(typeof raw == 'string'){
var matches = raw.match(/(\d+)-(\d+)-(\d+)/);
return new Date( +matches[1],
(+matches[2])-1,
+matches[3] );
}else if(raw instanceof Date){
return raw;
}
};

// A task model that has a date
can.Model("Task",{
attributes : {
due : 'date',
}
},{
weeksPastDue : function(){
return Math.round( (new Date() - this.due) /
(1000*60*60*24*7 ) );
}
});

// A contact model that has many tasks
can.Model("Contact",{
attributes : {
birthday : 'date',
tasks: "Task.models"
},
findAll : "/contacts.json"
},{
ageThisYear : function(){
return new Date().getFullYear() -
this.birthday.getFullYear()
},
getBirthday : function(){
return ""+this.birthday.getFullYear()+
"-"+(this.birthday.getMonth()+1)+
"-"+this.birthday.getDate();
}
});

// Get all contacts and put them on the page
Contact.findAll({},function(contacts){
var contactsEl = can.$('#contacts');

can.each(contacts, function(contact){
var li = can.$('<li>')
.html(contact.name + " "+ contact.ageThisYear())
.appendTo(contactsEl);

var ul = can.$("<ul>");
var tasks = contact.attr('tasks')

if(tasks){
tasks.each(function(){
this.attr('contact', contact);
ul.append('<li>'+this.title+" "
+this.weeksPastDue()+' contact: '+ this.attr('contact.name') +'</li>')
});
}

ul.appendTo(li)
});
});

 

Canjs 웹사이트



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

Javascript 모듈 관리엔 RequireJS

자바스크립트 모듈이 많아 관리가 어렵다면, RequireJS를 사용 해 보세요.

설정(Configuration)


require.config({
"baseUrl": "/static/js/vendor",
"paths": {
"app": "../app",
"bootstrap": [
'//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.1/js/bootstrap.min',
"bootstrap"
],
"jquery": [
"//ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min",
"jquery-1.9.1.min"
],
"can": "can",
shim: {
"bootstrap": {
deps: ["jquery"],
exports: "$.fn.popover"
},
enforceDefine: true
}
}
});

모듈 정의(define function)


define(["jquery"],function($){
return {
getParam: function(paramname){
var value = new RegExp('[\?&]' + param
name + '=([^&#]*)').exec(window.location.href);
return value[1];
},
test: function(text){
console.log("test : "+text);
}
};
});

두 모듈을 한 파일에 넣는 방법(requirejs, two classes in one file)

http://stackoverflow.com/questions/9806940/requirejs-two-classes-in-one-file

define('test', ['jquery'], function() {
var exports = {};
exports.test1 = {
method1 : function () {
console.log("test1 - method 1");
},
method2 : function () {
console.log("test1 - method 2");
}
};
exports.test2 = {
method1 : function () {
console.log("test2 - method 1");
},
method2 : function () {
console.log("test2 - method 2");
}
};

return exports;
});

그리고 아래처럼 사용하면 된다.
require(['test'], function (test) {
var test1 = test.test1;
});

두 모듈을 한 파일에 넣는 다른 방법
http://blog.credera.com/topic/technology-solutions/java/modular-javascript-with-requirejs


define(['json!data/customers'], function(customers){
var getRow = function(id) {
return customers[id];
};

var getAll = function() {
return customers;
};

var update = function(data) {
// do something cool with the data
};
return {
get: getRow,
list: getAll,
update: update
};
});


오류 해결

  • Jquery CDN경로가 올바르지 못할 경우 Bootstrap로딩에 오류가 난다.
  • 같은 모듈(예: bootstrap)이 중복 로드될 경우 충돌이 일어난다.

RequireJS 홈페이지



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

유용한 javascript 예제와 팁

URL 파라메터 받아오기(get PARAM)

http://www.codetreat.com/get-url-parameters-values-with-javascript

$.params = function(paramname){
var value = new RegExp('[\?&]' + param
name + '=([^&#]*)').exec(window.location.href);
return value[1];
}

Jquery 셀렉터 성능(JQUERY SELECTOR Performance)

http://jsperf.com/selectors-perf/6
cssSelector는 id 나 element와 함께 쓰지 않고 단독으로 사용한다.


var obj = document.getElementById("childDiv");
xxx = obj.getElementsByClassName("txtClass");

 

이벤트 처리

preventDefault() : 이벤트의 기본 행동을 막는다.
If this method is called, the default action of the event will not be triggered.
stopPropagation() : 상위 핸들러로 이벤트를 넘기지 않도록 막는다.
Prevents the event from bubbling up the DOM tree,
preventing any parent handlers from being notified of the event.

prepend() - 앞쪽에 내용을 붙인다.(to attach content as a prefix.)
append() - 뒷쪽에 내용을 붙인다. (to attach content as a suffix.)

배열 요소에서 데이터를 받고 싶을 땐 $()로 한번 더 감싼다.
$($(array_selector)[0]).data(something);


두번 submit되는 문제(prevent submit twice)
onclick이벤트 보다는 onsubmit 이벤트를 사용한다.
http://stackoverflow.com/questions/2830542/prevent-double-submission-of-forms-in-jquery

this.element.find('.save').attr('disabled','disabled');

// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
$(this).bind('submit',function(e){
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
e.preventDefault();
} else {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
}
// Keep chainability
return this;
};


JSON

Object to String
JSON.stringify(obj);
Parse JSON response
JSON.parse(obj);

JSON.parse()사용시 오류 : Uncaught SyntaxError: Unexpected token o
http://stackoverflow.com/questions/8081701/i-keep-getting-uncaught-syntaxerror-unexpected-token-o
데이터형이 올바르지 않아서 나는 오류이다.
Looks like jQuery takes a guess about the datatype.
It does the JSON parsing even though you're not calling getJSON()--
then when you try to call JSON.parse() on an object, you're getting the error.


loglevel

https://github.com/pimterry/loglevel
원하는 레벨의 로그를 콘솔 메시지로 보낸다.
켜고 끄는 것이 편리하다.
log.enableAll() and log.disableAll() methods.
* log.trace(msg)
* log.debug(msg)
* log.info(msg)
* log.warn(msg)
* log.error(msg)


JavaScript 디버깅

chrome dev tool -> Settings -> General -> Disable cache
Timeline을 이용하면 어떤 코드가 어플리케이션에 부하를 주는지 찾아준다.
메모리 누수가 발생한다면 찾아 개선한다.
Profiles도구에서 Heap Snapshot을 두 개 만들어 comparison view로 비교하면 성능 저하 원인을 찾기 편하다.



by


Tags : , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

자바스크립트용 개발 문서 작성기. JSDOC

주석 달기


/** define namespace
* @namespace category
*/

/** use namespace with hash
* @name category#name
* @constructor
*/

/** use member of for constructor
*@memberof category#name
*/


설정(configuration)

remove all comments.
// You must remove the comments before adding these options to your .json file

{
"tags":{
"allowUnknownTags":true
},
"source":{
"include":[],
"exclude":[],
"includePattern":".+\.js(doc)?$",
"excludePattern":"(^|\/|\\)_"
},
"plugins":[],
"templates":{
"cleverLinks":false,
"monospaceLinks":false
},
"opts":{
"template":"default", // same as -t default
"encoding":"utf8", // same as -e utf8
"destination":"./out/", // same as -d ./out/
"recurse":true, // same as -r
"tutorials":"path/to/tutorials",// same as -u path/to/tutorials, default "" (no tutorials)
"query":"value", // same as -q value, default "" (no query)
"private":true, // same as -p
"lenient":true, // same as -l
// these can also be included, though you probably wouldn't bother
// putting these in conf.json rather than the command line as they cause
// JSDoc not to produce documentation.
"version":true, // same as --version or -v
"explain":true, // same as -X
"test":true, // same as -T
"help":true, // same as --help or -h
"verbose":true, // same as --verbose, only relevant to tests.
"match":"value", // same as --match value, only relevant to tests.
"nocolor":true // same as --nocolor, only relevant to tests
}
}


실행
jsdoc -c conf.json

JSDOC github



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

파이썬 Flask 플러그인 안내와 팁.

데이터베이스
Flask-SQLAlchemy : OR매핑을 지원하는 플라스크용 파이썬 SQL toolkit
SQLAlchemy에서 상속(Inheritance) : http://docs.sqlalchemy.org/en/rel_0_7/orm/inheritance.html

SQLAlchemy 컬럼에 데이터가 생성될때나 업데이트 될때 현재 시각을 자동으로 넣는 방법.
updated_at = db.Column(db.DateTime, default=db.func.now(), onupdate=db.func.now())

로그인·보안
Flask-Social : 소셜 네트워크와의 연결을 간편하게 해 줌.
Flask Security(Auth) : 로그인과 권한관리.

관리자 페이지
Flask-Admin : 관리자 페이지를 손쉽게 만들도록 도와줌.

다국어 지원
Flask-Babel : 파이썬용 다국어 지원 Babel의 Flask 플러그인

캐쉬
flask-cache : 캐쉬 설정을 도와줌.

에셋 관리
flask-assets : 각종 static 에셋 관리를 편하게 도와줌.
사용하고자 하는 기능에 따라 추가 모듈이 필요하다. (css 압축, scss사용)
pip install cssmin
pip install pyscss
Flask-Assets extension에서 pyScss컴파일러 사용 설정법

from flask import Flask, render_template
from flask.ext.assets import Environment, Bundle

app = Flask(__name__)

assets = Environment(app)
assets.url = app.static_url_path
scss = Bundle('foo.scss', 'bar.scss', filters='pyscss', output='all.css')
assets.register('scss_all', scss)
And in the template include this:

{% assets "scss_all" %}
{% endassets %}

SCSS file은 debug모드에서도 컴파일 된다.

캐쉬
Flask-Cache : 플라스크에서 캐쉬 사용 하기 쉽게 도와줌.
# Flask-Cache Cache Type
CACHE_TYPE = 'simple' # 개발 시
CACHE_TYPE = 'redis' # 배포 시. redis 서버 구동 필요.
from flask.ext.cache import Cache

app = Flask(__name__)
cache = Cache()
cache.init_app(app, config={'CACHE_TYPE': CACHE_TYPE})

파일 업로드
Flask-Uploads : 파일 업로드 관련 처리를 도와줌.
from flask.ext.uploads import UploadSet
images = UploadSet()
images.__init__('upload', IMAGES)
filename = images.save(files, folder='/images', name='test.')
image_path = images.path(filename)
url = images.url(thumbnail)

텍스트 검색
Flask-WhooshAlchemy : 텍스트 기반 검색을 쉽게 도와줌

오류 추적
flask-exceptional : 오류 추적 서비스인 exceptional를 flask에서 이용 가능하게 도와줌.

전자상거래(e-commerce) [flask용 extension 아님]
stripe : 결제 모듈을 간편하게 시스템에 붙이도록 도와주는 서비스.
satchmoproject : 오픈소스 전자 상점 프레임워크 (satchmo Wiki)
satchless : 프레임워크에 종속적이지 않은 e-commerce용 클래스와 패턴 모음
flamaster : flask용 e-commerce eventing 시스템

Flask에서 JSON 다루기(JSON Handling in Flask)
http://flask.pocoo.org/docs/api/#module-flask.json

import requests
r = requests.get(QUERY_URL)
return r.json
//normal return
return jsonify(username=g.user.username,
email=g.user.email,id=g.user.id)

jsonify a SQLAlchemy result set in Flask
http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
jsonify의 문제는 object가 자동으로 json화 되지 않는다는 것이다.
serialize를 위해 다음을 모델에 추가 해 준다.


def dump_datetime(value):
"""Deserialize datetime object into string form for JSON processing."""
if value is None:
return None
return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")]

class Foo(db.Model):
//... SQLAlchemy defs here..
def __init__(self, ...):
//self.foo = ...
pass
@property
def serialize(self):
"""Return object data in easily serializeable format"""
return {
'id' : self.id,
'modified_at': dump_datetime(self.modified_at),
# This is an example how to deal with Many2Many relations
'many2many' : self.serialize_many2many
}
@property
def serialize_many2many(self):
"""
Return object's relations in easily serializeable format.
NB! Calls many2many's serialize property.
"""
return [ item.serialize for item in self.many2many]

뷰에서는 아래처럼 사용한다.

return jsonify(json_list=[i.serialize for i in qryresult.all()])

gunicorn서버 사용 설정.

from werkzeug.contrib.fixers import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app)

if __name__ == '__main__':
port = int(os.environ.get('PORT', 5000))
app.run()

Blueprint
routing관리에 이용한다.
application/feedback 폴더에 모듈을 넣을 경우.

from flask import Blueprint
mod = Blueprint('root', __name__, url_prefix='') // prefix를 공란으로 두면 root를 의미한다.
mod = Blueprint('feedback', __name__, url_prefix='/feedbacks') // prefix를 채우면 route('/')가 해당 prefix와 같다.
@mod.route('/')

새로운 디렉토리를 만들고 __init__.py파일을 추가해야 import시 인식한다.

모듈을 사용하려면 어플리케이션에서 등록해 준다.

from application.feedback.views import mod as feedbacksModule
app.register_blueprint(feedbacksModule)

파일 여러개 올리기(Uploading multiple files with Flask)
http://stackoverflow.com/questions/11817182/uploading-multiple-files-with-flask


@app.route("/upload", methods=["POST"])
def upload():
uploadedfiles = flask.request.files.getlist("file[]")
print uploadedfiles
return ""

동적으로 생성된 이미지 파일의 url 받기(How to get url for dynamically generated image file?)
http://stackoverflow.com/questions/12034949/flask-how-to-get-url-for-dynamically-generated-image-file

@app.route("/imgs/")
def images(path):
generateimg(path)
fullpath = "./imgs/" + path
resp = flask.makeresponse(open(fullpath).read())
resp.content_type = "image/jpeg"
return resp

mydomain.com/static/test.jpg

from flask import Flask, redirect, url_for

app = Flask(__name__)
@app.route('/')
def index():
generate_img("test.jpg"); #save inside static folder
return '<img src=' + url_for('static',filename='test.jpg') + '>'

Jade
두개의 속성을 지정할 땐 콤마(,)를 잊지 않는다.

script(data-main='js/app', src='js/vendor/require.js')



by


Tags : , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!

블로그 글 찾아보기를 편리하게! 월풍서가(月風書架)

블로그를 시작한 지 꽤 오랜 시간이 흘렀습니다.
가끔 예전에 쓴 글을 보고 싶은데, 글 제목이 생각 안 날 때가 있더라고요.
그래서 페이지를 하나 만들었습니다.
월풍서가(月風書架)
분류별로 글을 정리해 월풍도원 블로그 글을 찾아보기 쉽게 하기 위함입니다.
우선 책 감상평만 정리하였지만,
나머지 부분도 체계적으로 정리해 나갈 생각입니다.

오래전 글을 다시 읽는 재미가 쏠쏠합니다.
‘그 땐 저런 생각을 하고 살았구나.’
‘저건 불과 반 년 전인데도 낯설구나.’
이렇게 저를 돌아보며 블로그를 계속 써온 것에 뿌듯함을 느꼈어요.
월풍서가(月風書架)'
저에겐 지난날을 곱씹는 반추의 공간으로,
블로그를 찾으시는 분들께는 편리한 정보 검색 공간이 되게 하겠습니다.

저의 블로그를 찾아주셔서 고맙습니다.



by


Tags : , , , , , , ,

  • 재미있게 읽으셨나요?
    광고를 클릭해주시면,
    블로그 운영에 큰 도움이 됩니다!