프론트엔드에서 javascript 코드를 작성하면 모든 브라우저에서 인식 가능한 javascript로 바꿔주는 뭔가 필요하는데 이 때 사용하는 것이 webpack이다. 더 상세히 쉽게 말하자면 최신 자바스크립트를 작성하여 다른 브라우저와 호환성이 있는 코드로 바꿔주는 작업을 할것이다.
npm i webpack webpack-cli -D
Webpack을 설정하기 위해서는 webpack.config.js라는 파일을 생성해야한다. 참고로 이 파일은 굉장히 오래된 javascript 코드만 이해할 수 있다. 따라서 import를 사용할수없고 required를 사용해주어야한다.
그리고 package.json에 빌드 명령어를 입력해주어야한다.
"assets": "webpack --config webpack.config.js"
Front에서 사용할 스크립트 연결과 스크립트 빌드 방법
webpack.config에는 두가지 주의점이 있는데.
하나는 entry이다. entry는 우리가 처리하고자 하는 파일들이다. 모든 파일들에는 entry가 필요하고 output도 필요하다
//src
////
entry
| client // 프론트 관련 폴더
| scripts // 프론트 관련 JS or TS
| scss // 프론트 관련
////
| 그밖의 백엔드 괄련 폴더들
| 그밖의 백엔드 괄련 폴더들
| 그밖의 백엔드 괄련 폴더들
| 그밖의 백엔드 괄련 폴더들
| 그밖의 백엔드 괄련 폴더들
| views
| server.ts or js
| db.ts or js
module.exports = {
entry: "./src/client/scripts/main.ts",
};
그리고 이제 output 결과물을 위해 파일명을 정해줘야한다. 또한 파일을 어디에 저장할지도 정해줘야한다.
웹팩은 상대경로가 아닌 절대경로로 작성해주어야한다. 그러기 위해서는 path 불러와서 설정해주어야한다.
// 잘못된 예시
module.exports = {
entry: "./src/client/scripts/main.ts",
output: {
filename: "main.js",
path: "./dist/js",
},
};
const path = require("path");
module.exports = {
entry: "./src/client/scripts/main.ts",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist", "js"),
},
};
Rules
rules는 우리가 각각의 파일 종류에 따라 어떤 전환을 할 건지 결정하는 것이다.
특정파일을 가지고 변환시킬껀데 이 변환들을 적용시키기 위해서는 loader가 필요하다.
const path = require("path");
module.exports = {
entry: "./src/client/scripts/main.ts",
devtool: "inline-source-map",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist", "js"),
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "ts-loader",
}, //js는 babel-loader
exclude: /node_modules/,
},
],
},
};
ts 사용자는 Ts config도 손좀 봐야하는데 아래 예시는 정답이 아닐수가 있다.
{
"compilerOptions": {
"target": "es5",
"module": "es6",
"moduleResolution": "Node",
"sourceMap": true,
"outDir": "./dist/",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitAny": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"],
"exclude": ["node_modules"]
}
npm run 빌드 명령어를 입력후 mode option과 관련된 경고가 뜨는데 이는 코드가 지금 개발 중인지 완성품인지 알려 줘야한다. 백엔드를 서버에 직접 올릴 때가 되면 바꾸어야 한다. mode 설정을 안해주면 기본적으로 webpack은 production mode로 설정된다. 이는 파일이 압축되므로 개발중일때 우리가 어디서 틀렸는지 확인하기가 어렵다.
const path = require("path");
module.exports = {
entry: "./src/client/scripts/main.ts",
mode: "development",
devtool: "inline-source-map",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist", "js"),
},
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "ts-loader",
},
exclude: /node_modules/,
},
],
},
};
이렇게 한후 다시 빌드명령어를 입력하고 빌드된 파일을 보면 압축되어있지 않은 모습을 볼수있다.
이제 express에게 빌드한 폴더 안에 스크립트 파일이 있다고 알려주어야한다.
Nodejs / Express에서 upload 폴더에 접근할수 있게 만든것 처럼 작성해주어야한다. express 서버에
// 사용할 url / 사용할 스크립트가 들어있는 폴더명
app.use("/dist", express.static("dist"));
pug를 사용한다면 script src='/dist/js/main.js'로 프론트엔드 를 사용해주자
CSS
css를 사용하기 위해 client 폴더에 css폴더를 만든다. 만들기 앞서 scss 라는 폴더로 만들자 간단하게 확인할 수있게 bgColor설정을 주고 저장 그리고 클라이언트에 사용할 스크립트 파일(빌드 전 파일)에 import해준다.
다음으로 이것을 Webpack으로 loader로 통해 화면에 나올수 있게 해주어야한다. 이를 위해 세가지 Loader가 필요하다
- scss가져다가 일반 css로 변형해주는 loader // sass-loader
- https://github.com/webpack-contrib/sass-loader
GitHub - webpack-contrib/sass-loader: Compiles Sass to CSS
Compiles Sass to CSS. Contribute to webpack-contrib/sass-loader development by creating an account on GitHub.
github.com
- 뭔가를 불러오는것을 가능하게 만들어주는 loader (@import 랑 url() 따위를 풀어서 해석해주는 것이다.)
- https://webpack.js.org/loaders/css-loader/
css-loader | webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
webpack.js.org
- 변환한 css를 웹사이트에 적용시킬 loader (css를 Dom) 에 주입
- https://webpack.js.org/loaders/style-loader/
style-loader | webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
webpack.js.org
이렇게 많은 loader들을 적을 땐 array로 담아서 작성하면 된다. 중요한것은 순서인데 webpack은 뒷순서부터 loader를 사용할 것이다.
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
CSS Part Refactor
위와 같이 작업을 진행하게 되면 javascript 내부에 스타일이 들어가게 된다. 브라우저가 로딩이 될때 스크립트를 맨 마지막에 하게 되는데 이때 스타일도 같이 마지막에 로딩이 될것이다. 그래서 파일을 따로 분리 시키는게 좋을지도 모른다.
MiniCssExtractPlugIn
https://webpack.js.org/plugins/mini-css-extract-plugin/#root
MiniCssExtractPlugin | webpack
webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.
webpack.js.org
해서 위의 플러그인을 설치 plugin 하면 안되고 무조건 plugins라고 해야한다.
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/client/scripts/main.ts",
mode: "development",
devtool: "inline-source-map",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist", "js"),
},
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "ts-loader",
},
exclude: /node_modules/,
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
};
폴더 분할
빌드 명령을 내리게되면 같은 폴더에 main.js 와 main.css가 공존하게 된다. 유지보수 및 관리를 위해 폴더를 분할 해주는 것이 좋다.
MiniCssExtractPlugin을 문서를 살펴보면 파일 경로를 지정해줄수 있다. plugins에 new MiniCssExtractPlugin()에 가서 입력해주자
npm run assets을 다시 입력하면 덮어쓰이기가 되기 때문에 파일이 중복될수 있다. 그러니 빌드한 폴더를 지우고 다시 빌듬명령을 내려주자
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/client/scripts/main.ts",
mode: "development",
devtool: "inline-source-map",
output: {
filename: "js/main.js",
path: path.resolve(__dirname, "dist"),
},
plugins: [new MiniCssExtractPlugin({ filename: "css/styles.css" })],
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "ts-loader",
},
exclude: /node_modules/,
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
};
pug를 사용한다면 빌드된 styles.css를 link해주자
개발환경 개선
매번 dist 파일을 지웠다가 빌드명령어를 입력하는게 여간 귀찮은 일이다. 이것을 해결하기위해 webpack에 watch라는 기능을 true로 넣어두면 빌드 명령어가 계속해서 동작을하며 파일이 새로 저장될때마다 바로 피드백이 된다. 또한 clean:true로 빌드 명령어 시작전에 dist 폴더를 자동으로 지워주고 빌드해줄수있게 할 수 있다.
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: "./src/client/scripts/main.ts",
mode: "development",
watch: true,
devtool: "inline-source-map",
output: {
filename: "js/main.js",
path: path.resolve(__dirname, "dist"),
clean: true,
},
plugins: [new MiniCssExtractPlugin({ filename: "css/styles.css" })],
module: {
rules: [
{
test: /\.ts$/,
use: {
loader: "ts-loader",
},
exclude: /node_modules/,
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
},
],
},
};