1️⃣
🖥 NPM
1 - 1. 프로젝트 생성
- 프론트엔드 개발에 Node.js가 필요한 이유
-
- 최신 스펙으로 개발할 수 있다.
-
- 빌드 자동화
-
- 개발환경 커스터마이징
- 노드 설치
- 노드로 서버를 운영 : 왼쪽의 LTS버전
-
개발환경을구축 : 오른쪽의 최신버전
-
터미널에 $node 입력 -> 노드 터미널 도구 열림 : REPL ( 자바스크립트 코드를 입력하고 즉시 확인할 수 있는 프로그램 ) -> 종료시 $ .exit
- $ npm init ( 프로젝트 생성 명령어 )
- package name -> 프로젝트 이름 / 쭉 엔터 치고 나면 package.json 이 생성된 것을 볼 수 있다.
-
package.json / scripts : 프로젝트를 자동화 할 수 있는 shell script 를 입력할 수 있는 부분
- 프로젝트 명령어
- Error: no test specified -> 이러한 문자열을 echo 명령어로 출력 , 에러코드 1번을 반환하는 shell script, 일종의 샘플 스크립트
- 스크립트 실행 -> $ npm test -> 등록한 shell script가 실행!
- 기본적 제공 커멘드 외에 추가하고 싶다면 ?
- 커스텀 스크립트를 실행할때는 $ npm run 커멘드이름
1 - 2. 외부 패키지를 관리하는 방법
- 패키지 설치
-
- CDN( 컨텐츠 전송 네트워크 ) 방식
-
- 직접 다운로드
-
- npm 을 이용한 방법 / $ npm install 라이브러리 -> package.json 파일에 dependencies 부분이 추가된다.
- 유의적 버전과 버전의 범위
- 유의적 버전(Sementic Version)
- 주 버전(Major Version): 기존 버전과 호환되지 않게 변경한 경우
- 부 버전(Minor version): 기존 버전과 호환되면서 기능이 추가된 경우
- 수 버전(Patch version): 기존 버전과 호환되면서 버그를 수정한 경우
위의 내용은 https://jeonghwan-kim.github.io/series/2019/12/09/frontend-dev-env-npm.html 블로그내용 복붙
"dependencies": {
"react": "^16.13.1"
}
- 위와 같은 코드에서는 16 - 주버전 / 13 - 부버전 / 1 - 수버전
-
이처럼 버전 번호를 관리하는 방법을 유의적버전 / node.js 는 유의적 버전 규칙을 따른다
- 버전의 범위
- 단순한버전은 숫자만 입력 / 특정버전보다 낮거나 높을때는 >, >=, <, <=
- 틸드(~)와 캐럿(^)
- 틸드 : 마이너 버전이 명시되어있다면 패치버전을 변경한다. 예를 들어 ~1.2.3 은 1.2.3 부터 1.3.0 미만까지 / 마이너버전이 없으면 마이너버전을 갱신 / ~0 표기는 0.0.0 부터 1.0.0 미만까지를 포함
- 캐럿 : 정식버전일경우에 마이너와 패치버전을 변경. 예를들어 ^1.2.3 이면 1.2.3 부터 2.0.0 미만까지 / 하지만 정식버전 미만인 0.x 버전은 패치만 갱신 / ^0 표시는 0.0.0 부터 0.1.0 미만까지를 포함
🖥 웹팩(Webpack) - 기본편
2 - 1. 웹팩이 필요한 이유와 기본 동작
// math.js
function sum(a, b){
return a + b;
}
// app.js
console.log(sum(1, 2));
- 위와 같은 방식은 전역스코프가 오염된다.
- sum은 math 안에서만 유효한것이 아닌 어느곳에서도 다 접근할 수 있다
-
따라서 전역스코프 오염 -> 예측할 수없게 됨 -> 런타임에러
- 즉시실행함수 - 스코프사용 ( 안에서만 사용가능 (외부에서는 접근하지 못한다)-> 전역스코프오염 x )
// math.js
var math = math || {};
(function(){
function sum(a, b){
return a + b;
}
math.sum = sum;
})()
// app.js
console.log(math.sum(1, 2));
- 이러한 방식으로 js 모듈을 구현하는 대표적인 명세가 AMD 와 CommonJS
CommonJS는 자바스크립트를 사용하는 모든 환경에서 모듈을 하는 것이 목표다. exports 키워드로 모듈을 만들고 require() 함수로 불러 들이는 방식이다. 대표적으로 서버 사이드 플래폼인 Node.js에서 이를 사용한다.
AMD(Asynchronous Module Definition)는 비동기로 로딩되는 환경에서 모듈을 사용하는 것이 목표다. 주로 브라우져 환경이다.
- commonJs + AMD -> UMD
- 이후 ES2015 표준모듈시스템
// math.js
export function sum(a, b){
return a + b
}
// app.js
import * as math from './math'
console.log(math.sum(1, 2));
- 모든 브라우저에서 모듈시스템을 지원하지 않기때문에 아래와 같이 추가해준다.
// index.html
<script type="module" src="app.js"></script>
html 파일을 바로 열고싶을때 $ open index.html(파일이름) 간단하게 서버를 킬때 $ npm lite-server
2 - 2. 엔트리/아웃풋 실습
- 모듈로 연결된 여러개의 자바스크립트파일을 하나로 합쳐주는 역할 -> 웹팩
- 이렇게 하나로 합쳐진 파일 -> 번들 ( 웹팩이 번들을 만드는 번들러 역할을 하는것 / 웹팩 = 번들러)
- 웹팩(번들작업), 웹팩 cli(웹팩을 터미널명령으로 사용할 수 있는) 설치 / $ npm install -D webpack webpack-cli
- 위에서 설치시 -D 옵션을 주었기때문에 package.json devDependencies 에서 확인 가능하다.
- devDependencies : 개발용 패키지
- 설치후 node_modules > .bin > webpack, webpack-cli 설치되어있음을 확인할 수 있다.
$ node_modules/.bin/webpack –help
- webpack 필수요소
- 1️⃣ –mode : “development”, “production”, “none” / 개발환경이냐 운영환경이냐에 따라 설정
- 개발용 정보 추가 -> development / 운영에 배포하기위한 최적화 설정 -> production
- 2️⃣ –entry : 모듈의 시작점 / 엔트리를 지정해줘야함 ( 필수 )
- 엔트리를 통해서 웹팩이 모든 모듈을 하나로 합치고 그 결과를 저장하는경로를 -> output
- 3️⃣ –output, -o : 결과 저장하는 경로 설정 옵션
- 세가지 옵션으로 우리 코드를 번들링 해보자.
- $ node_modules/.bin/webpack –mode development –entry ./src/app.js –output dist/main.js
- 위의 사진같은 결과를 얻을 수 있다.
- 매번 명령어를 입력할때마다 터미널을 긴 옵션을 줄 수 없기때문에 webpack 설정 파일을 만든다.
- config 파일 명: webpack.config.js or webpackfile.js
// webpack.config.js
const path = require('path') // node 모듈
module.exports = {
// module.exports -> node 의 모듈 시스템
mode: "development",
entry: {
main: "./src/app.js",
// 경로 뿐만 아니라 main 이라는 key 값도 설정
},
output: {
path: path.resolve("./dist"),
// path 는 output 디렉토리명을 입력, 절대경로 입력
filename: "[name].js",
// entry에서 설정한 key값으로 설정( ex main)
// entry 가 여러개일수도있기때문에, 동적으로 만들어내기위해 [name] 으로 설정
},
};
- npm -> 프로젝트를 관리하는, 스크립트를 자동화 해주는 기능
- 웹팩으로 번들링 해주는 과정을 npm 스크립트의 등록 -> package.json scripts build : ‘webpack’
- 이렇게 적어주면 npm은 현재 프로젝트에 있는 node modules 에서 웹팩을 찾는다.
- $ npm run build
- entry 는 자바스크립트 모듈이 의존관계가 있는데 그 시작점!
- webpack 은 그 시작점을 기준으로 모든 모듈을 찾아서 하나의 파일로 번들 -> 결과를 output 에 설정.
2 - 3. 엔트리와 아웃풋(실습)
2 - 4. 엔트리와 아웃풋(풀이)
-
- package.json 파일이 없는 상태 -> $ npm init -y (-y:기본값을 다 사용)
-
- webpack 설치 -> $ npm install webpack webpack-cli
-
- webpack 명령어 추가 -> package.json scritps build:’webpack’ 추가
-
- webpack.config.js 생성 -> mode, entry, output !!
-
- index.html 에 빌드한 파일 넣어주기 ->
2 - 5. 로더
- 😶로더의 역할
- 웹팩은 js 파일 뿐만아니라 모든 파일을 모듈로 바라본다. 그렇기때문에 import 구문을 사용하면 js 코드 안으로 가져올수 있다.
-
이것이 가능한 이유는 웹팩에 로더가 있기 때문 ( 웹팩에서 로더가 하는일 : 모든 파일을 자바스크립트에 모듈처럼 만들어 준다. )
- 😶커스텀 로더 만들기
- 로더는 함수형태로 작성하고, webpack.config.js 에 module 객체에 rules 라는 배열에 추가할 수 있다.
// my-webpack-loader.js
module.exports = function myWebpackLoader(content){
// 로더는 함수형태로 작성한다.
console.log('myWebpackLoader 작동함');
return content;
}
// webpack.config.js
const path = require('path')
module.exports = {
mode: "development",
entry: {
main: "./src/app.js"
},
output: {
path: path.resolve('./dist'),
filename: "[name].js"
},
module: {
rules: [
{
test: /\.js/$,
// test : 로더가 처리해야할 파일의 패턴 (정규표현식)
// js로 끝나는 모든 파일
use: [
path.resolve('./my-webpack-loader.js')
]
// use : 사용할 로더 명시
// 모든 자바스크립트 코드에 대해서 my-webpack-loader 가 실행되게끔 하는 설정
}
]
}
}
2 - 6. 자주 사용하는 로더
- 😶css-loader
- css 파일을 위한 로더 / js 에서 css 파일을 모듈로 불러올 수 있다.
- $ npm install css-loader
test: /\.css$/,
use: [
'css-loader'
]
- 웹팩은 css 파일을 만나면, css-loader 를 동작하게 된다. -> css-loader 가 css 파일을 처리하게 한다.
- 하지만 아직 js 안에 css 가 있기만 해서 작동하지는 않는다 ( html->css 불러오거나 / 인라인스크립트여야 css 가 읽힌다.)
- $ npm install style-loader
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
- 스타일로더 : 자바스크립트로 변경된 스타일코드를 html에 넣어준다. -> webpack.config.js 에 추가해준다.
-
로더는 한파일에서 여러개 실행되는데, use 순서는 뒤에서 앞으로 !
- 로더는 css 뿐만 아니라, import 구문을 이용해서 이미지도 받아올수 있다.
- $ npm install file-loader (이미지 처리)
test: /\.png$/,
use: [
'file-loader'
]
webpack 은 빌드 할때마다 유니크한 값을 생성 -> 해쉬값 캐쉬갱신을 위해 / 정적파일의 경우 브라우저에서 캐쉬 흔함 js, img, css, font 등 성능을 위해 캐쉬 -> 파일내용이 달라지고 이름이 같으면 이전의 캐쉬로 저장했던 내용을 브라우저가 사용 -> 이를 예방하는 방법중 하나가 이름을 변경
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
publicPath: './dist/',
name:'[name].[ext]?[hash]'
}
// publicPath : 파일로드가 처리하는 파일을 모듈로 사용했을때 경로앞에 추가되는 문자열
// 우리는 output 을 dist로 설정했기때문에 여기서도 dist
// 파일을 호출할때 앞에 dist 를 붙이고 호출한다.
// name : 파일로더가 파일아웃풋에 복사할때 사용하는 파일이름
// 원본파일명 = [name], 확장자명 = [ext],
}
-
위와같이 추가, 변경해주면 img 를 잘 받아온다.
- 😶url-loader
- 이미지갯수가 많은, 작은파일을 base64로 인코딩해서 js 문자열로 변환하는 로더
- data URI scheme
- $ npm install url-loader
// app.js
import './app.css';
import nyancat from './nyancat.jpg'
document.addEventListener('DOMContentLoaded', ()=>{
document.body.innerHTML = `
<img src="${nyancat}" />
`
})
// 돔이 만들어 졌을때 이미지태그를 추가
// webpack.config.js
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
publicPath: './dist/',
name:'[name].[ext]?[hash]',
limit: 20000, //20kb
}
// limit : 파일 용량 셋팅, 20kb 미만의 파일은 url-loader 로 base64로 변환
// limit 이상일때는 file-loader 실행
// limit 미만은 js 문자열로 변환 / 그 이상은 파일로 복사
}
2 - 7. 로더(실습)
"scripts": {
"build": "webpack --progress"
},
- –progress : 빌드 상태를 커멘드라인에 표시
2 - 8. 로더(풀이)
-
- css-loader, style-loader 설치 $ npm install css-loader style-loader
-
- webpack.config.js module 등록
-
- app.js 에서 main.css 를 받아올수있게된다.
-
- file-loader 를 통해 위와 같이 img 를 받아올수있게 한다. (이때는 loader, options 필요)
-
- 작은 파일은 url-loader를 이용한다.
$ rm -rf dist : dist 폴더 삭제
2 - 9. 플러그인
-
로더가 파일 단위로 처리하는 반면, 플러그인은 번들된 결과물을 처리한다.
- 😶커스텀 플러그인 만들기
- 로더가 함수로 정의했던것과 다르게, 플러그인은 클래스로 정의
- my-webpack-plugin.js 파일 생성
// my-webpack-plugin.js
class MyWebpackPlugin {
// js 에서 클래스를 만들때 앞은 대문자로 !
apply(compiler) { // 플러그인의 메소드
compiler.hooks.done.tap("My Plugin", stats => {
// 플러그인이 완료됬을때 동작하는 콜백함수
console.log("MyPlugin: done")
})
}
}
module.exports = MyWebpackPlugin
// webpack.config.js
const MyWebpackPlugin = require('./my-webpack-plugin')
plugins: [
// 플러그인은 plugins 라는 배열에 추가
// 이후 만든 클래스 생성자 함수를 가져온다
new MyWebpackPlugin(),
]
- 위 처럼 커스텀 플러그인을 웹팩 설정에 추가 ( 로더처럼 )
// my-webpack-plugin.js
// compiler.plugin() 함수로 후처리한다
compiler.plugin("emit", (compilation, callback) => {
const source = compilation.assets["main.js"].source()
// 그중 main.js 소스코드를 가져오는 함수.
compilation.assets['main.js'].source = () => {
const banner = [
'/**',
' * 이것은 BannerPlugin이 처리한 결과입니다.',
' * Build Date: 2019-10-10',
' */'
].join('\n');
return banner + '\n' + source;
}
callback()
})
// compilation 을 통해서 웹팩이 빌드한 결과물에 접근할수있다.
}
- 위와 같이 하면 빌드된 main.js 상단에 banner 가 박힌것을 확인할 수 있다.
- 웹팩의 로더는 각파일을 처리해서 하나로 만드는데, 그 직전에 플러그인이 개입해서 아웃풋으로 만들어질 번들링의 후처리를 해준다.
2 - 10. 자주 사용하는 플러그인
- 😶Banner plugin
- 커스텀으로 만들었던 플러그인 -> 실제로는 banner plugin
- 빌드한 결과물에 빌드 정보나 커밋버전을 추가할수있는 플러그인
- 웹팩에서 기본으로 제공하는 플러그인
// webpack.config.js
const webpack = require('webpack')
plugins: [
new webpack.BannerPlugin({
// 객체 전달
banner: '이것은 배너입니다.'
})
]
- $ npm run build 하면 아래와 같은 결과물을 build/main.js 에서 확인할 수 있다.
- 터미널 명령어 결과를 banner에 넣어줄수있다.
// webpack.config.js
const webpack = require('webpack')
const childProcess = require('child_process')
//childProcess 를 이용해서 터미널명령어를 확인할 수있다.
plugins: [
new webpack.BannerPlugin({
// 객체 전달
banner: `
Build Date: ${new Date().toLocaleString()}
Commit version: ${ childProcess.execSync('git rev-parse --short HEAD') }
Author: ${childProcess.execSync('git config user.name')}
`
})
// childProcess.execSync('터미널명령어를 넣어준다.')
]
- 😶Define plugin
- 환경에따라 API 서버 주소가 다를 수 있다.
- API 주소처럼 환경의존적인 정보를 소스가 아닌 다른 곳에서 관리하는것이 좋다.
- 환경 변수들을 어플리케이션에 제공하기 위해서 Define plugin 사용
- Banner plugin 처럼 Define plugin 도 웹팩의 기본 플러그인이다.
// webpack.config.js
const webpack = require('webpack')
plugins: [
new webpack.DefinePlugin({
TWO:'1+1',
// 어플리케이션에서는 TWO 라는 전역변수로 접근할수있고, '1+1' 은 코드이기때문에 2 가 찍힌다.
TWOTWO:JSON.stringify('1+1')
// 코드가 아닌 값을 넣고싶다면 위와 같이 JSON.stringify 이용
'api.domain': JSON.stringify('http://dev.api.donmain.com')
// 위와 같은 형태의 객체타입도 지원한다.
})
]
// src/app.js
console.log(process.env.NODE_ENV); // -> webpack.config.js 에서 mode: "development"이기때문에 development 가 찍힌다.
console.log(TWO); // -> 2 가 찍힘
console.log(TWOTWO); // -> 1 + 1 찍힘
console.log(api.domain); // -> http://dev.api.donmain.com 찍힘
- 😶Html Template plugin
- 웹팩의 기본 플러그인이 아닌 써드파티패키지 ( 설치해야함 )
- html 파일 후처리하는데 사용
- $ npm install html-webpack-plugin
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
new HtmlWebpackPlugin({
// 옵션을 전달할때 template 경로를 전달할수있다.
template: './src/index.html'
}),
- index.html 을 src 안으로 옮기고 기존
- 작성하지 않은 코드가 dist/index.html 에 추가 되어있는것을 볼 수 있다. </body>
- 이렇듯 html 플러그인을 쓰면 빌드 과정에 html도 포함되기 때문에 의존적이지 않은 코드로 html을 만들 수 있다.
- 기존 img를 불러왔던 로더에서도 수정을 해주었다.
// webpack.config.js
{
test: /\.(png|jpg|gif|svg)$/,
loader: "url-loader",
options: {
// publicPath: "./dist/",
// dist/index 로 경로가 바꼈기때문에 publicpath 를 지워줘도 가능
},
},
- 또한 development 일때만 타이틀에 (개발용)을 붙이고 싶다면
// index.html
<title>Document <%= env %></title>
<!-- <%= env %> : ejs 문법 / env라는 변수를 넣을수있는 템플릿 문법 -->
// webpack.config.js
new HtmlWebpackPlugin({
template: './src/index.html',
templateParameters: {
env : process.env.NODE_ENV === 'development' ? '(개발용)' : ''
}
}),
- $ NODE_ENV=development npm run build 하면 타이틀에 개발용이 붙은것을 확인할 수 있다.
- 뿐만아니라, html을 압축하고 주석을 제거하는 기능도 존재
// webpack.config.js
new HtmlWebpackPlugin({
//...
minify: {
collapseWhitespace: true,
// 공백 제거
removeComments: true
// 주석 제거
}
}),
- 만약 운영환경에서만 minify 옵션을 키고 싶다면 ??
// webpack.config.js
new HtmlWebpackPlugin({
//...
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true,
removeComments: true
} : false
}),
- 😶clean Webpack plugin
- 웹팩의 기본 플러그인이 아니라 따로 설치 필요
- output 폴더를 삭제해준다. ( dist )
- $ npm install clean-webpack-plugin
// webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// CleanWebpackPlugin 은 default export 되어 있지 않기때문에 {} 에 넣어준다.
plugins: [
//... 웹팩 플러그인들
new CleanWebpackPlugin()
],
- 😶mini css extract plugin
- 번들결과에서 스타일시트 코드만 따로 뽑아서 css 파일을 별도로 만들어 역할을 따로 분리하는것이 좋다.
- 따로 설치 필요
- $ npm install mini-css-extract-plugin
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
plugins: [
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === 'production'
? [new MiniCssExtractPlugin({ filename: '[name].css' })] // filename: 생성될 파일이름
: [])
// 나머지 연산자 이용
// 환경변수에 따라서 플러그인을 키거나 끌수있다.
// 다른 플러그인과 다르게 로더를 설정해주어야 한다.
],
// 이후 css 로더도 수정해주어야한다.
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === 'production'
? MiniCssExtractPlugin.loader
: "style-loader",
"css-loader"
],
},
],
},
- $ NODE_ENV=production npm run build -> dist/main.css 가 생긴것을 확인할 수 있다.
- dist/index.html 에도 css 가 추가된것을 알수있다.
⌨️정리
- banner plugin : 번들링된 결과물 상단에 빌드 정보를 추가
- define plugin : 빌드 타임에 결정되는 환경변수를 어플리케이션 단에 주입하기 위해 사용 / API 주소
- html template plugin : 빌드과정에 html을 넣음. html파일을 동적으로 만들어내는데 사용
- clean webpack plugin : 빌드 할때마다 output(dist)폴더를 삭제해줌
- mini css extract plugin : 번들된 js코드에서 css 파일만 따로 뽑아내서 css 파일을 만들어내는 플러그인