Jello's development blog

Jello's development blog

bower와 pipeline을 이용한 Django 의존성, 배포 관리

들어가며

Django 뿐만 아니라 웹 프레임워크로 개발을 하다 보면, 프론트엔드(javascript) 부분의 의존성을 관리해줘야 한다. AngualrJs나 ReactJs, BackboneJs 경우에는 프론트엔트 프레임워크이므로 bower나 npm의 package.json으로 관리하고, minify, concat, uglify, compress등을 해주는 컴파일러는 grunt나 webpack, browserify 등으로 관리하면 해결된다.

하지만 Django처럼 백엔드와 프론트엔드 모두를 아우르는 프레임워크는 어떻게 해야 할까? 이것은 웹 프레임워크마다 다른데, Django같은 경우에는 virtualenv가 Python package를 관리하고, django-bower라는 python 패키지가 프론트엔드 의존성을 관리해준다. bower가 django전용으로 존재한다니.. 얼마나 많은 사람들이 이런 고민을 했는지 느껴지는 순간이었다.

그렇다면 배포를 도와주는 빌드 툴은 무엇이 있을까? 바로 django-pipeline이 유명한 Django 프론트엔드 빌드 툴 중 하나이다. 이는 bower에서 관리하는 의존성 패키지들을 배포용으로 압축할 수 있게 도와준다. 그렇다면 이제 bower, pipeline을 Django에 적용해보자

Django-bower 설치, 적용하기

django-bower docs 에도 나와있듯이, 적용하기 전에 먼저 관련 package를 설치해야한다.
Django용으로 나와있는 것을 설치하기 전에, 먼저 원래 node의 모듈으로 있는 bower 먼저 설치해야 한다.

$ npm install -g bower

전역으로 bower를 설치한 후에, Python package를 virtualenv에 설치한다. (virtualenv 환경 구축하기)

(ENV_NAME)$ pip install django-bower

설치가 끝난 뒤에는 Django의 settings.py파일을 수정해야 한다.
먼저 INSTALLED_APPSSTATICFILES_FINDERS에 항목을 아래처럼 추가한다.

INSTALLED_APPS = [
	...
	'djangobower'
]

# STATICFILES_FINDERS 변수가 없다면 새로 만들어서 추가한다.
STATICFILES_FINDERS = [
	...
	'djangobower.finders.BowerFinder'
]

BOWER_COMPONENTS_ROOT 변수를 새로 만들고, 새로운 package들이 설치될 디렉토리를 설정한다.
설정된 디렉토리에 bower_components라는 디렉토리가 생기고, 그 안에 package들이 설치된다.
반드시 absolute path로 설정해야 한다.

BOWER_COMPONENTS_ROOT = os.path.join(BASE_DIR, '../')

마지막으로 bower에 설치할 package 이름을 적어준다. #[VERSION]을 적으면 버전을 고정시킬 수 있다.

BOWER_INSTALLED_APPS = [
    'jquery#1.9',
    'underscore',
]

settings.py 설정이 모두 끝났다!
이제 위에서 명시해준 package들을 설치해보자.

(ENV_NAME)$ python manage.py bower install

위 명령을 실행하면 지정된 디렉토리에 package들이 설치된다.
아래 명령어를 통해 Django에 쓰일 static폴더가 생성된다.

(ENV_NAME)$ python manage.py collectstatic
[...]

위에서 STATICFILES_FINDERS'djangobower.finders.BowerFinder'을 넣어주었기 때문에 manage.py가 bower_components를 찾을 수 있는 것이다.
이를 제거하고 collectstatic을 한다면 Django는 bower_components 안에 있는 package들을 인식하지 못한다.

이렇게 BOWER_INSTALLED_APPS에 설치할 package들을 명시해줌으로써 웹 서비스에 필요한 프론트엔드 package들을 관리할 수 있다.

Django-pipeline 설치, 적용하기

이제는 배포를 하기 위해서 javascript와 css를 빌드해보자. 여기서 빌드 작업은 javascript파일이나 css파일을 압축하거나(minify), 읽기 힘들게 바꿔줘서(uglify) 용량을 작게 만들고, 코드 파악이 어렵도록 만든다.
또한 css의 경우 scss(sass), less로 작성된 파일을 css로 precompile하거나, javascript의 경우 .jsx 파일을 .js파일로 precompile해주거나, es6버전을 es5버전으로 낮춰주는 기능을 수행한다.

먼저 virtualenv에 django-pipeline을 설치한다.

[ENV_NAME]$ pip install django-pipeline

settings.pyINSTALLED_APPS를 다음과 같이 설정한다. django-bower에 이어서 추가하면 된다.

INSTALLED_APPS = [
	...
	'django-bower',
    'pipeline'
]

STATICFILES_STORAGE을 다음과 같이 설정하고, 이전에 추가했던 STATICFILES_FINDERS파일에 BowerFinder를 제거한 뒤에, pipeline.finders.PipelineFinder를 추가한다.
또한 STATICFILES_DIRS을 다음과 같이 추가한다.

STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'

STATICFILES_FINDERS = [
    ...
    'pipeline.finders.PipelineFinder'
]

STATICFILES_DIRS = [
	os.path.join(BASE_DIR, 'static'),
	os.path.join(BOWER_COMPONENTS_ROOT, 'bower_components')
]

pipeline은 STATICFILES_DIRS 안에 있는 항목들을 static 파일로 인식하고, 설정에 따라서 빌드해준다.
따라서 첫 번째 항목으로 django project 안에 있는 static 디렉토리를 추가했고, bower로 받은 package도 빌드하기 위해서 BOWER_COMPONENTS_ROOT를 추가했다.

이제 pipeline이 어떻게 빌드를 해야하는지 설정해야한다.
settings.py에 다음과 같이 추가한다.

PIPELINE = {
    'STYLESHEETS': {
        'colors': {
            'source_filenames': (
              'css/core.css',
              'css/colors/*.css',
              'css/layers.css'
            ),
            'output_filename': 'css/colors.css'
        },
    },
    'JAVASCRIPT': {
        'stats': {
            'source_filenames': (
              'js/jquery.js',
              'js/d3.js',
              'js/collections/*.js',
              'js/application.js',
            ),
            'output_filename': 'js/stats.js',
        }
    }
}

STYLESHEETS는 css나 scss, less등을 설정하는 항목이고, JAVASCRIPT는 말 그대로 javascript를 설정하는 항목이다.
위의 예시와 같이 설정했다면, collectstatic을 했을 시에 지정해준 static 파일에 css/colors.css, js/stats.js파일이 빌드되어 있음을 확인 할 수 있다.
빌드가 성공적으로 수행되었다면 다음과 같은 태그로 빌드된 파일을 django template에서 불러올 수 있다.

{% load pipeline %}
{% stylesheet 'colors' %}
{% javascript 'stats' %}

먼저 맨 위에 load pipline으로 ‘내가 이 템플릿에 pipeline을 사용할 것이다’라는 것을 알려주고, settings.py에 설정해 준 이름을 불러오면 된다.
자세한 빌드 설정 방법은 django-pipeline docs을 참고하면 된다.

마치며

현재 pipelineFinder로 찾은 모든 static 파일은, collectstatic을 실행하게 되면 빌드 하기 전과 후 파일 모두 복사하게 되는데, 빌드된 파일만 복사하고 빌드하기 전 파일은 복사하지 않게 할 방법을 찾고 있는데, 아직 찾지 못했다. 조금 더 docs를 살펴보아야겠다.

django-pipelinedjango-bower를 사용해 보면서 Django가 역시나 굉장히 많이 쓰이는 웹 프레임워크라고 생각했다. 사용법이 편리했고, docs에 자세한 설명이 나와있었다. 하지만 크기가 크고 지원하는 기능이 많은 프레임워크인 만큼, ‘django-‘가 붙은 그들만의 package들이 너무 많다는 것이다. 이들을 익히면 Django에서만 쓸 수 있고, 다른 곳에서는 쓸 수 없기 때문에 제한적이라고 생각되었다.