NodeJS 공부하면서 처음 세팅해본 gulp 입니다.
여러가지 HTML Template를 사용하려고 시도했습니다.
아직 미완성입니다.
Jade(Pug), ejs, sass 공부가 충분치 않다는 걸 느꼈습니다.
<html lang="ko"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title><%= title %></title> <style> body { font-size: 12pt; color: #006666; } h1 { font-size: 18pt; background-color: #AAFFFF; } pre { background-color: #EEEEEE; } </style> </head> <body> <% var title = 'ejs' %> <h1><%= title %></h1> <p>Welcome to <%= title %>, 오잉 되네? 아싸 문법정리만 하자, 사용법만 확실하게 익히고 lastRun도 추가하고</p> <button class="<%= title %>" type="submit">전송</button> <input type="text" placeholder="<%= title + '연습' %>"> EJS에서 변수는 <%= %>로 감쌉니다. <br> 내부에 변수를 사용할 수도 있습니다. <br> 자바스크립트 코드는 <% %> 안에 적어줍니다. </body> </html>
<html lang="ko"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title><%= title %></title> <style> body { font-size: 12pt; color: #006666; } h1 { font-size: 18pt; background-color: #AAFFFF; } pre { background-color: #EEEEEE; } </style> </head> <body> <% var title = 'ejs' %> <h1><%= title %></h1> <p>Welcome to <%= title %>, 오잉 되네? 아싸 문법정리만 하자, 사용법만 확실하게 익히고 lastRun도 추가하고</p> <button class="<%= title %>" type="submit">전송</button> <input type="text" placeholder="<%= title + '연습' %>"> EJS에서 변수는 <%= %>로 감쌉니다. <br> 내부에 변수를 사용할 수도 있습니다. <br> 자바스크립트 코드는 <% %> 안에 적어줍니다. </body> </html>
<html lang="ko"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title><%= title %></title> <style> body { font-size: 12pt; color: #006666; } h1 { font-size: 18pt; background-color: #AAFFFF; } pre { background-color: #EEEEEE; } </style> </head> <body> <% var title = 'ejs' %> <h1><%= title %></h1> <p>Welcome to <%= title %>, 오잉 되네? 아싸 문법정리만 하자, 사용법만 확실하게 익히고 lastRun도 추가하고</p> <button class="<%= title %>" type="submit">전송</button> <input type="text" placeholder="<%= title + '연습' %>"> EJS에서 변수는 <%= %>로 감쌉니다. <br> 내부에 변수를 사용할 수도 있습니다. <br> 자바스크립트 코드는 <% %> 안에 적어줍니다. </body> </html>
<html lang="ko"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title><%= title %></title> <style> body { font-size: 12pt; color: #006666; } h1 { font-size: 18pt; background-color: #AAFFFF; } pre { background-color: #EEEEEE; } </style> </head> <body> <% var title = 'ejs' %> <h1><%= title %></h1> <p>Welcome to <%= title %>, 오잉 되네? 아싸 문법정리만 하자, 사용법만 확실하게 익히고 lastRun도 추가하고</p> <button class="<%= title %>" type="submit">전송</button> <input type="text" placeholder="<%= title + '연습' %>"> EJS에서 변수는 <%= %>로 감쌉니다. <br> 내부에 변수를 사용할 수도 있습니다. <br> 자바스크립트 코드는 <% %> 안에 적어줍니다.4444 </body> </html>
- /sp/
doctype html block lang - var language = 'ko' html(lang=language === 'ko' ? 'ko-KR' : language === 'en' ? 'en' : '') include _head body.dark-theme include _navigation | 안녕?
head meta(http-equiv="X-UA-Compatible", content="IE=Edge") block metatags meta(name="author", content="hyungju") meta(name="viewport", content="width=device-width, initial-scale=1") title block pageTitle | -title- //-block stylesheets //- link(rel="stylesheet", href="css/style.css") style include ../../../dist/css/style.css script(src="js/libs/libs.js") script include ../../../dist/js/DOMlibrary.min.js
//- 현재 페이지 경로 -var curPage='/' //- 믹스인 2Depth 정의 mixin navi2D(naviContents2) nav: ul each D1_item in naviContents2 li +naviLink(D1_item) if D1_item.child ul each D2_item in D1_item.child li +naviLink(D2_item) mixin naviLink(item) a(href=item.link)=item.content+curPage
//- script 정의 block scripts script(src="js/libs/libs.js")
extends parts/_docTemplate block lang - var language = 'ko-KR' block pageTitle | 안녕하세요1
- /libs/
// Scss 한줄 주석 /* Scss 여러줄 주석, CSS로 컴파일 될 때 해석됩니다. */ %btn { padding: 10px; border: 1px solid #222; } .btn-check { @extend %btn; background-color: #cecece; } .btn-click { @extend %btn; background-color: $fg-color; }
// 테마 변수 : light | dark $theme: dark; // 조건 처리 @if $theme == light { $bg-color: #f34e7b; } @else if $theme == very-light { $bg-color: #f8c9d6; } @else { $bg-color: #61051f; } // 테마 클래스 속성 및 // 배경/전경 컬러 색상 설정 body.#{$theme}-theme { background-color: $bg-color; color: invert($bg-color); } // if(조건, 참일 경우 값, 거짓일 경우 값) // 가운데 정렬 유무 설정 $center-pos: false; $is-center: if($center-pos, auto, null); .container { @include margin(null, $is-center); }
// 페이지 폭 $page-width: 960px; // 컬럼 개수 $columns: 24; // 거터 $gutter: 20px; // 컬럼 폭 $col-width: (($page-width - $gutter) - ($gutter*($columns - 1))) / $columns; %col { float: left; margin-right: $gutter; } // 조건이 3보다 작거나 같으면 코드 반복 생성 @for $i from 1 through $columns { .col-#{$i} { @extend %col; width: ($col-width * $i) + ($gutter * ($i - 1)); } } // --------------------------------------------- /* 아이콘(icon) 설정 */ // --------------------------------------------- @each $item, $w, $h in (git, 24px, 24px), (nodejs, 32px, 32px), (gulpjs, 24px, 24px), (jade, 16px, 16px) { .icon-#{$item} { width: $w; height: $h; background-image: url("images/#{$item},png"); } } // --------------------------------------------- /* 제목(Heading) 설정 */ // --------------------------------------------- @each $H in (h1:3rem, h2:2rem, h3:1.7rem, h4:1.5rem, h5:1.3rem, h6:1rem) { #{nth($H, 1)} { font-size: nth($H, 2); } }
@mixin reset-list { padding-left: 0; list-style: none; } @mixin html5-block { section, article, nav, aside, header, footer { display: block; } } @mixin position($type:relative, $t:null, $l:null, $b:null, $r:null) { position: $type; top: $t; left: $l; bottom: $b; right: $r; } @mixin size($w:null, $h:null) { width: $w; height: $h; } @mixin transition($args...) { transition: $args; } @mixin transform($args...) { transform: $args; } @mixin margin($tb:null, $lr:null) { margin: { top: $tb; bottom: $tb; left: $lr; right: $lr; } }
- _sprite.scss
// 폰트 $ghothic: "Nanum Gothic", Dotum, Sans-serif; $myungjo: "Nanum Myungju", Gulim, serif; // 색상 $fg-color: #382f1f; $bg-color: #fefcf5;
*, *::before, *::after { box-sizing: border-box; } html, body { height: 100%; } nav { background-color: #222; } #page { width: 100%; margin: 0 auto; padding: 30px; .article { position: relative; margin: { right: 10px; left: 30px; } } .container { padding-left: 5%; padding-right: 5%; } a { text-decoration: none; color: #069aea; &:hover { padding-bottom: 0.1rem; color: #023855; } .rgba & { color: rgba(6, 154, 234, 0.8); } } }
@import "modules/_sprite"; /* 필요한 거 1배수만 가져오기 */ .arrow-r { @include sprite($arrow-r); } /* 필요한 것만 1, 2배수 가져오기 */ .arrow-r { @include retina-sprite($arrow-r-group); } /* 1배수 이미지 모두 */ @include sprites($spritesheet-sprites); /* 1, 2배수 이미지 모두 */ @include retina-sprites($retina-groups);
@charset "utf-8"; @import "modules/_variables"; @import "modules/_button"; @import "pages/_page1"; @import "modules/_mixins"; @import "modules/_condition"; @import "modules/_loop"; @include html5-block; nav ul, #gbn ul, #lnb ul { @include reset-list; font-family: $myungjo; color: $bg-color; } .login-box { @include position(absolute, 0, 10px); @include size(24rem, 10rem); } /* 주석 */ .error { @include position($type: absolute, $r: 10px); @include size(320px); @include transition(width 0.2s, height 0.4s ease-out); @include transform(scale(1.5)); }
<html lang="ko"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title></title> </head> <body> </body> </html>
{ "presets": [ "@babel/preset-env" ] }
{ "env": { "browser": true, "es6": true, "node": true }, "extends": "eslint:recommended", "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, "rules": { } }
.idea/ node_modules/ dist/ package-lock.json
{ "port": 90, "livereload": true, "browser": "chrome", "path": { "del": { "dest": "dist/" }, "browser": { "dest": "dist/" }, "jade": { "src": "src/jade/**/!(_)*.jade", "parts": "src/jade/parts/*.jade", "dest": "dist/jade/" }, "ejs": { "src": "src/ejs/**/!(_)*.{ejs,html}", "parts": "src/ejs/parts/*.ejs", "dest": "dist/ejs/" }, "sass": { "src": "src/sass/**/*.{scss, sass}", "compassSrc": "src/sass/", "dest": "dist/css/" }, "js": { "libs": "src/js/libs/**/*.js", "libsDest": "dist/js/libs/", "src": "src/js/*.js", "dest": "dist/js/", "filename": "DOMlibrary.js" }, "img": { "src": "src/img/*", "dest": "dist/img/" }, "spImg": { "src": "src/img/sp/*.png", "dest": "dist/img/sp/", "filename": "sprite.png", "imgPath": "../img/sp/sprite.png" }, "retinaImg": { "src": "src/img/sp/*@2x.png", "filename": "sprite@2x.png", "retinaImgPath": "../img/sp/sprite@2x.png" } } }
"use strict"; // 모듈 호출 // gulp : gulp 모듈 // gulp-eslint : javascript 문구 문법 검사 // gulp-concat : javascript 파일을 한 파일로 합쳐주는 모듈 // gulp-uglify : javascript 파일을 min 파일처럼 압축해주는 모듈 // gulp-babel : es6를 es5로 컴파일 해주는 모듈 // gulp-rename : 파일의 이름을 바꿔주는 모듈 // gulp-jade : HTML 템플릿 중 하나인 jade 템플릿을 사용할 수 있게 하는 모듈 // gulp-ejs : HTML 템플릿 중 하나인 ejs 템플릿을 사용할 수 있게 하는 모듈 // gulp-sass : sass를 사용할 수 있게 해주는 모듈 // gulp-clean-css : css 파일을 이쁘게 압축해주는 모듈 // del : 폴더(디렉터리)/파일 제거 // gulp-connect : local 서버와 연결하게 해주는 모듈 // gulp-open : 브라우저를 열게하는 모듈 // gulp-sass-lint : sass 문법검사 모듈 // autoprefixer : vend prefix를 자동으로 달아주는 모듈 // gulp-postcss : 위 autoprefixer와 같이 쓰는 모듈 // gulp-imagemin : image 파일 용량을 줄여주는 모듈 // gulp.spritesmith : sprite 이미지와 CSS 자동 생성 모듈 // vinyl-buffer : gulp.spritesmith 모듈과 gulp-imagemin 모듈을 연결시켜주는 모듈 // merge-stream : stream을 merge시켜주는 모듈, 종료신호를 묶어서 보낼 수 있다. import fs from 'fs'; import {src, dest, watch, series, parallel, lastRun} from 'gulp'; import esLint from 'gulp-eslint'; import jsConcat from 'gulp-concat'; import jsUglify from 'gulp-uglify'; import babel from 'gulp-babel'; import rename from 'gulp-rename'; import jade from 'gulp-jade'; import ejs from 'gulp-ejs'; import sass from 'gulp-sass'; import cleanCss from 'gulp-clean-css'; import del from 'del'; import connect from 'gulp-connect'; import open from 'gulp-open'; import sassLint from 'gulp-sass-lint'; import autoprefixer from 'autoprefixer'; import postcss from 'gulp-postcss'; import imagemin from 'gulp-imagemin'; import spritesmith from 'gulp.spritesmith'; import buffer from 'vinyl-buffer'; import merge from 'merge-stream'; import config from './config.json'; // 테스트 중인 기능 export const fsReadDir = () => { let fileList; let fileList2 = []; fileList = fs.readdirSync('./src/ejs/', { encoding: 'utf8', withFileTypes: true }); fileList.forEach(function (file, index) { if (!file.isDirectory()) { fileList2.push(file.name) } }); console.log(fileList); console.log(fileList[0].isDirectory()); console.log(fileList[3].isDirectory()); console.log(fileList2); }; /* * For small tasks you can export arrow functions */ // 파일 삭제 export const Clean = () => { return del( [config.path.del.dest] ); }; // 이미지 용량 줄이기 및 sprite export const SpriteAndImgCompress = () => { const imgCompress = src(config.path.img.src) .pipe(imagemin([ imagemin.gifsicle({interlaced: true}), imagemin.mozjpeg({quality: 80, progressive: true}), imagemin.optipng({optimizationLevel: 5}), imagemin.svgo({ plugins: [ {removeViewBox: true}, {cleanupIDs: false} ] }) ])) .pipe(dest(config.path.img.dest)); const spriteData = src(config.path.spImg.src) .pipe(spritesmith({ retinaSrcFilter: config.path.retinaImg.src, imgName: config.path.spImg.filename, retinaImgName: config.path.retinaImg.filename, imgPath: config.path.spImg.imgPath, retinaImgPath: config.path.retinaImg.retinaImgPath, cssName: '_sprite.scss', padding: 2 })); const imgStream = spriteData.img .pipe(buffer()) .pipe(imagemin()) .pipe(dest(config.path.spImg.dest)); const cssStream = spriteData.css .pipe(dest('src/sass/modules/')); return merge(imgCompress, imgStream, cssStream); }; // Sass 컴파일 // 주의할 점, Jade 템플릿과 어떻게 연동했냐에 따라서 watch 함수 내부를 수정해줄 필요가 있다. // Jade 템플릿에 style 태그에 인라인 형식으로 불러왔으면 watch 형식에서 Jade 탬플릿까지 수정을해줘야하는 함수를 호출해야한다. const Sass = () => { return src(config.path.sass.src, {sourcemaps: true}) .pipe(sassLint({ options: { formatter: 'stylish' } })) .pipe(sassLint.format()) .pipe(sass({ sourceComments: false, // source 위치 주석 outputStyle: 'compact' // nested, expanded, compact, compressed }).on('error', sass.logError)) .pipe(postcss([autoprefixer()])) .pipe(cleanCss({format: 'keep-breaks'})) .pipe(dest(config.path.sass.dest, {sourcemaps: true})) .pipe(connect.reload()) }; // JS 문법 검사 const HintJs = () => { return src(config.path.js.src) .pipe(esLint()) .pipe(esLint.format()) }; // JS 병합 const ConcatJs = () => { return src(config.path.js.src) .pipe(jsConcat(config.path.js.filename)) .pipe(babel()) .pipe(dest(config.path.js.dest)); }; // JS 압축 const UglifyJs = () => { return src(config.path.js.dest + config.path.js.filename, {sourcemaps: true}) .pipe(jsUglify()) .pipe(rename({suffix: '.min'})) .pipe(dest(config.path.js.dest, {sourcemaps: true})) .pipe(connect.reload()) }; // JS libs 내보내기 const Libs = () => { return src(config.path.js.libs) .pipe(dest(config.path.js.libsDest)) .pipe(connect.reload()) }; // Jade 컴파일 const JadeCompile = () => { return src(config.path.jade.src, {since: lastRun(JadeCompile)}) .pipe(jade({ pretty: true })) .pipe(dest(config.path.jade.dest)) .pipe(connect.reload()) }; // ejs 컴파일 const EjsCompile = () => { return src(config.path.ejs.src, {since: lastRun(EjsCompile)}) .pipe(ejs({ msg: "Hello Gulp!" })) .pipe(rename({ extname: ".html" })) .pipe(dest(config.path.ejs.dest)) .pipe(connect.reload()) }; // 웹 서버 업무 (LiveReload 사용) const Server = () => { return connect.server({ root: config.path.browser.dest, port: config.port, livereload: config.livereload }) }; // 브라우저 오픈 업무 const BrowserOpen = () => { const options = { uri: `http://localhost:${config.port}`, app: config.browser //chrome, firefox, iexplore, opera, safari }; return src(config.path.browser.dest) .pipe(open(options)); // local 서버가 아닌 파일 경로로 열려면 '<%file.path%>' 를 넣어주면된다. }; // 지속적 관찰(Watch) 업무 정의 // Jade Template 내부 인라인 형식으로 들어가게 했을지도 모르므로 다음과 같이 모든 함수 뒤에 JadeCompile 함수를 호출하였다. const FileWatch = () => { watch([config.path.img.src, config.path.spImg.src], SpriteAndImgCompress); watch([config.path.jade.src, config.path.jade.parts], JadeCompile); watch([config.path.ejs.src, config.path.ejs.parts], EjsCompile); watch(config.path.sass.src, series(Sass, JadeCompile, EjsCompile)); watch(config.path.js.src, series(HintJs, ConcatJs, UglifyJs, JadeCompile, EjsCompile)); watch(config.path.js.libs, Libs, JadeCompile, EjsCompile); }; /* * You could even use `export as` to rename exported tasks */ exports.build = series(Clean, series(Libs, SpriteAndImgCompress), parallel(Sass, series(HintJs, ConcatJs, UglifyJs)), JadeCompile, EjsCompile); /* * You could even use `export as` to rename exported tasks */ exports.watch = parallel(Server, BrowserOpen, FileWatch); /* * Export a default task */ exports.default = series(Clean, series(Libs, SpriteAndImgCompress), parallel(Sass, series(HintJs, ConcatJs, UglifyJs)), JadeCompile, EjsCompile, parallel(Server, BrowserOpen, FileWatch));
{ "name": "sass-training", "version": "1.0.0", "description": "", "main": "gulpfile.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "devDependencies": { "@babel/core": "^7.8.4", "@babel/preset-env": "^7.8.4", "@babel/register": "^7.8.3", "autoprefixer": "^9.7.4", "babel-cli": "^6.26.0", "babel-preset-env": "^1.7.0", "babel-register": "^6.26.0", "del": "^5.1.0", "ejs": "^3.0.1", "eslint": "^6.8.0", "gulp": "^4.0.2", "gulp-babel": "^8.0.0", "gulp-clean-css": "^4.2.0", "gulp-concat": "^2.6.1", "gulp-connect": "^5.7.0", "gulp-ejs": "^5.0.0", "gulp-eslint": "^6.0.0", "gulp-imagemin": "^7.1.0", "gulp-jade": "^1.1.0", "gulp-open": "^3.0.1", "gulp-postcss": "^8.0.0", "gulp-rename": "^2.0.0", "gulp-sass": "^4.0.2", "gulp-sass-lint": "^1.4.0", "gulp-uglify": "^3.0.2", "gulp.spritesmith": "^6.11.0", "merge-stream": "^2.0.0", "node-sass": "^4.13.1", "vinyl-buffer": "^1.0.1" }, "browserslist": [ "last 2 version", "> 2%", "IE 9", "IE 8" ] }