티스토리 뷰
웹팩 개발서버
개발환경과 운영환경을 맞춤으로써 배포시 잠재적 문제를 미리 확인할 수 있다.
프론트엔드 개발환경에서 이러한 개발용 서버를 제공해주는 것이 Webpack-dev-server 이다.
npm install Webpack-dev-server
package.json
{
"scripts": {
"start": "webpack-dev-server --progress"
}
}
--progress
를 추가하면 빌드 진행률을 보여준다.
기본 설정
웹팩 설정 파일의 devServer 객체에 개발 서버 옵션을 설정할 수 있다.
webpack.config.js
module.exports = {
devServer: {
// 아웃풋
contentBase: path.join(__dirname, "dist"),
// 브라우저를 통해 접근하는 경로
publicPath: "/",
// 개발환경에서 도멘을 맞추어야 하는 상황에서 아용
host: "dev.domain.com",
// 빌드, 에러시 경고를 브라우저에 표시
overlay: true,
// 포트
port: 8081,
// 메세지 수준
stats: "errors-only",
// 히스토리 API 를 사용하는 SPA 개발시 설정한다. 404 발생시 index.html로 리다이렉트 한다.
historyApiFallback: true,
},
}
API 연동
프론트엔드에서는 서버와 데이터를 주고 받기 위해 ajax 를 사용하는데 보통 ajax 서버를 어딘가에 띄워 놓고 프론트 서버와 함께 개발한다.
devServer 에 before 라는 속성을 사용하여 처리할 수 있는데, 이 미들웨어는 익스프레스를 사용할 수 있다.
// webpack.config.js
module.exports = {
devServer: {
before: (app, server, compiler) => {
app.get("/api/keywords", (req, res) => {
res.json([
{ keyword: "이탈리아" },
{ keyword: "세프의요리" },
{ keyword: "제철" },
{ keyword: "홈파티" },
])
})
},
},
}
connect-api-mocker 를 사용하여 목업 api 작업이 방대한 경우 사용할 수 있다.
npm install connect-api-mocker
// webpack.config.js:
const apiMocker = require("connect-api-mocker")
module.exports = {
devServer: {
before: (app, server, compiler) => {
app.use(apiMocker("/api", "mocks/api"))
},
},
}
첫번째 인자는 설정할 라우팅 경로인데 /api로 들어온 요청에 대해 처리하겠다는 의미다. 두번째 인자는 응답으로 제공할 목업 파일 경로인데 방금 만든 mocks/api 경로를 전달했다.
목업 API 갯수가 많다면 직접 컨트롤러를 작성하는 것 보다 목업 파일로 관리하는 것을 추천한다.
프록시
다른 url 로 호출하면 CORS 정책 때문이라는 메시지가 나온다. 리소스에 Access-Control-Allow-Origin 이 없어서 나오는 에러인데,
해결하는 방법은 여러가지가 있다.
- 응답부분에서
res.header("Access-Control-Allow-Origin", "*")
헤더를 추가한다. - cors 미들웨어를 설치하여 셋팅해준다.
- 웹팩 개발서버에 프록시 속성을 사용하여 서버를 설정해준다.
// webpack.config.js module.exports = { devServer: { proxy: { "/api": "http://localhost:8081", // 프록시 }, }, }
개발 서버에 들어온 모든 http 요청 중 /api 로 시작되는 것은 8081 서버로 요청하는 설정이다.
핫 모듈 리플레이스먼트
웹팩 개발서버는 코드의 변화를 감지해서 전체 화면을 갱신하기 때문에 개발속도를 높일 수 있다.
하지만, 어떤 상황에서는 전체 화면을 갱신하는 것이 좀 불편한 경우도 있다. SPA 는 브라우저에서 데이터를 들고 있기 때문에
리프레시 후에 모든 데이터가 초기화 되어버리기 때문이다.
전체 화면이 갱신되는 것이 아닌, 변경한 모듈만 바꿔치기할 수 있도록 하는 것이 핫 모듈 리플레이스먼트이다.
설정
// webpack.config.js:
module.exports = {
devServer = {
hot: true,
},
}
import form from "./form";
import result from "./result";
if (module.hot) {
console.log("핫 모듈 켜짐");
module.hot.accept("./result", async () => {
console.log("result 모듈 변경 됨");
resultEl.innerHTML = await result.render();
});
module.hot.accept("./form", () => {
formEl.innerHTML = form.render();
});
}
되면, result, form 에 대한 모듈 변경이 일어나면 hot 아래 에 콜백함수가 전달되어 브라우저 갱신 없이 부분 화면이 갱신되는 것을 볼 수 있습니다.
최적화
코드가 많아지면 번들링된 결과물도 커지기 마련이다. 메가바이트 단위까지 커질 수 있는데 이러면 브라우저 성능에 영향을 줄 수 있다.
productuin
웹팩에 내장되어 있는 방법 중 mode 값을 설정하는 방식이 가장 기본이다.process.env.NODE_ENV
값이 "development" 로 설정되어 어플리케이션에 전역변수로 주입된다.
반면 mode 를 "production" 으로 설정하면 자바스크립트 결과물을 최소화해준다.
그렇기에 환경변수에 따라 mode 를 설정해줄 수 있다.
const mode = process.env.NODE_ENV || "development"
module.exports = {
mode
}
{
"scripts": {
"start": "webpack-dev-server --progress",
"build": "NODE_ENV=production webpack --progress"
}
}
optimazation 속성을 이용하여 css 파일도 합축해줄 수 있다.
npm install optimize-css-assets-webpack-plugin
terser-webpack-plugin 은 자바스크립트 코드를 난독화하고 debugger 구문을 제거한다.
npm install terser-webpack-plugin
externals 속성을 사용하여 빌드 과정에서 번들에 포함하지 않고 빌드 할 수 있도록 추가한다.
그렇게 하기 위해서는 externals: { axios: "axios" }
를 사용하고 node_modules 에서 index.html 로 로딩해주어야 한다.
이는 CopyWebpackPlugin
을 설치한다.
npm install copy-webpack-plugin
const CopyPlugin = require("copy-webpack-plugin")
module.exports = {
plugins: [
new CopyPlugin([
{
from: "./node_modules/axios/dist/axios.min.js",
to: "./axios.min.js", // 목적지 파일에 들어간다
},
]),
],
}
최종
const path = require("path");
const webpack = require("webpack");
const childProcess = require("child_process");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtreactPlugin = require("mini-css-extract-plugin");
const apiMocker = require("connect-api-mocker");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const mode = process.env.NODE_ENV || "development";
module.exports = {
mode,
// 시작점을 기준으로 모든 모듈을 찾아 번들링 해줌.
entry: {
main: "./src/app.js",
},
// 번들링한 결과를 아웃풋에 전달합니다.
output: {
// 절대경로
path: path.resolve("./dist"),
filename: "[name].js",
},
devServer: {
overlay: true,
stats: "errors-only",
before: (app) => {
app.use(apiMocker("/api", "mocks/api"));
},
hot: true,
},
optimization: {
minimizer:
mode === "production"
? [
new OptimizeCSSAssetsPlugin(),
new TerserPlugin({
terserOptions: { compress: { drop_console: true } },
}),
]
: [],
// splitChunks: {
// chunks: "all"
// }
},
externals: {
axios: "axios",
},
module: {
rules: [
{
// 각 js 파일당 로더가 한 번 씩 호출됨.
test: /\.css$/,
// loader use
use: [
process.env.NODE_ENV === "production"
? MiniCssExtreactPlugin.loader
: "style-loader",
"css-loader",
],
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: "url-loader",
options: {
// publicPath: './dist/',
name: "[name].[ext]?[hash]",
limit: 20000, // 20kb (파일 용량 제한), 이상이면 file-loader가 자동으로 실행됨.
},
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
},
],
},
plugins: [
// new MyWebpackPlugin()
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")}
`,
}),
new webpack.DefinePlugin({
// 코드 형식
TWO: "1+1",
// 문자열 형식
TWO2: JSON.stringify("1+1"),
// 객체 형식
"api.domain": JSON.stringify("http://dev.api.domain.com"),
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
templateParameters: {
env: process.env.NODE_ENV === "development" ? "(개발용)" : "",
},
minify:
process.env.NODE_ENV === "production"
? {
collapseWhitespace: true,
removeComments: true,
}
: false,
}),
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === "production"
? [new MiniCssExtreactPlugin({ filename: "[name].css" })]
: []),
new CopyPlugin([
{
from: "./node_modules/axios/dist/axios.min.js",
to: "./axios.min.js",
},
]),
],
};
- Total
- Today
- Yesterday
- docker
- 네이버 서치 어드바이저
- vue router
- Vite
- 깃허브
- dockerfile
- nextjs14
- Storybook
- nextjs13
- Embedding
- NUXT
- React
- 티스토리챌린지
- 오블완
- 서버 to 서버
- vscode
- 스벨트
- nodejs
- Git
- seo
- nuxt2
- svelte
- 타입스크립트
- cors
- NextJS
- openAI
- webpack
- vue composition api
- AWS
- Github Actions
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |