๋ฒ๋ค๋ฌ ์ค ํ๋๋ก ์ฌ๋ฌ ํ์ผ์ ์์ถํด์ฃผ๋ ๋ฒ๋ค๋ง ์ญํ ์ ํ๋ ๋์
์นํฉ ๊ด๋ จ ๋ค์ดํ ๊ฒ
1. webpack : core ํจํค์ง
2. webpack-cli : ํฐ๋ฏธ๋ ๋์ ์ํฌ ๊ฒ
3. webpack-dev-server : ๊ฐ๋ฐ ์๋ฒ ์คํ์ฉ
์ฌ์ดํธ๋ฅผ ๋ค์ด๊ฐ๋ฉด ๊ธฐ๋ณธ์ ์ธ package.json๋ถํฐ ์ ๋ถ ์์ฑ๋์ด์๋ค.
{
"name": "webpack-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "cross-env NODE_ENV=production webpack --progress",
"start": "webpack serve --progress"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.13.10",
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.10",
"@vue/compiler-sfc": "^3.2.19",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^8.0.0",
"core-js": "^3.9.1",
"cross-env": "^7.0.3",
"css-loader": "^5.1.1",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.3.0",
"mini-css-extract-plugin": "^1.3.9",
"node-sass": "^5.0.0",
"sass-loader": "^11.0.1",
"source-map-loader": "^2.0.1",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.1.1",
"url-loader": "^4.1.1",
"vue": "^3.2.19",
"vue-loader": "^16.8.1",
"webpack": "^5.24.3",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^3.11.2"
}
}
babel๋ถํฐ ์์ํด์ css์ sass ๊ทธ์ธ์
html-webpack-plugin์ webpack๊ด๋ จ๋ ์ค๋น๋์ด์๋ค.
webpack
webpack-cli
webpack-dev-server
style-loader
sass-loader
css-loader
html-webpack-plugin
vue
vue-loader
@vue/compiler-sfc
์นํฉ ์ค์ ํ์ผ
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const { VueLoaderPlugin } = require('vue-loader')
const webpackMode = process.env.NODE_ENV || 'development';
module.exports = {
mode: webpackMode,
resolve : {
extensions : ['.vue', '.js'],
alias : {
'~' : path.resolve(__dirname , 'src')
}
},
entry: {
main: './src/main.js',
},
output: {
path: path.resolve('./dist'),
filename: '[name].js'
},
// es5๋ก ๋น๋ ํด์ผ ํ ๊ฒฝ์ฐ ์ฃผ์ ์ ๊ฑฐ
// ๋จ, ์ด๊ฑฐ ์ค์ ํ๋ฉด webpack-dev-server 3๋ฒ๋ ๋ฒ์ ์์ live reloading ๋์ ์ํจ
// target: ['web', 'es5'],
devServer: {
overlay: true,
stats: 'errors-only',
liveReload: true
},
optimization: {
minimizer: webpackMode === 'production' ? [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true
}
}
})
] : [],
splitChunks: {
chunks: 'all'
}
},
// externals: {
// ๋น๋ ๊ณผ์ ์์ ์ ์ธํ๊ณ ๊ทธ๋๋ก ์ฌ์ฉํ ํจํค์ง ์ง์
// ์์ - foo๋ผ๋ ์ด๋ฆ์ ๋ชจ๋์ด๋ผ๋ฉด ์๋์ฒ๋ผ ์
๋ ฅ
// foo: "foo"
// },
module: {
rules: [
{
test: /\.(css|scss)$/,
use: [
process.env.NODE_ENV === 'production' ? MiniCssExtractPlugin.loader : 'style-loader',
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'url-loader',
options: {
name: '[name].[ext]?[hash]',
limit: 10000,
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.js$/,
enforce: 'pre',
use: ['source-map-loader'],
},
{
test : /\.vue$/,
use : 'vue-loader'
}
]
},
plugins: [
new webpack.BannerPlugin({
banner: `
LICENSE.txt์ ์ถ๋ ฅํ ๋ด์ฉ
`
}),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: process.env.NODE_ENV === 'production' ? {
collapseWhitespace: true,
removeComments: true,
} : false
}),
new CleanWebpackPlugin(),
...(process.env.NODE_ENV === 'production'
? [new MiniCssExtractPlugin({ filename: '[name].css' })]
: []
),
new VueLoaderPlugin(),
// ๋น๋ ๋ js์ ํฌํจ์ํค์ง ์๊ณ ๊ทธ๋๋ก ๊ฐ์ ธ์์ ์ฐ๋ ํ์ผ์ ์๋์ฒ๋ผ ์ค์ ํ๊ณ , HTML์๋ ์ง์ ๋ฃ์ด์ฃผ์ธ์
// new CopyPlugin({
// patterns: [
// { from: "./src/ext/modernizr.js", to: "./modernizr.js" },
// ],
// })
]
};
extensions๋ฅผ ํตํด .vue๋ .js์ ๋ค์ ํ์ผ๋ช ์ ์๋ตํ ์ ์๋ค.
alias๋ฅผ ํตํด ์ด๋ค ๋ฌธ์์ ๋ํด path๋ฅผ ์ง์ ํด ์ค ์ ์๋ค.
ํ์ผ์ ์ฒ๋ฆฌํ ๋์
ํ์ผ์ ์ฒ๋ฆฌํด ์ถ๋ ฅํ ์์น(path)์ ๋์(filename)
์ด๋ ํ ํ์ผ์ ๋ํด ์ด๋ ํ loader๋ฅผ ์ด์ฉํ์ฌ ์ฒ๋ฆฌํ ์ง
test๋ฅผ ํตํด ํ์ผ๋ช ์ ์ง์ ํ๊ณ
loader๋ use๋ฅผ ํตํด ํด๋น loader๋ฅผ ์ง์ ํ๋ค
webpack์ผ๋ก ๋ณํํ ํ์ผ์ ์ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ์ ๋ํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
์ฃผ์ : vue ๊ด๋ จ ๋ค์ด ๋ฐ์ ๋
npm i -D vue@next vue-loader@next @vue/compiler-sfc
๋ก ์ต์ ๋ฒ์ @next
๋ฅผ ์ฌ์ฉํด์ผํ๋ค.
- index.html
- main.css
- main.js
- App.vue
- component/Btn.vue
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
๋งค์ฐ ๊ฐ๋จํ๊ฒ app id๋ฅผ ๊ฐ์ง divํ๊ทธ๋ง ์กด์ฌ
.name{
background-color:orange;
width:300px;
height:100px;
}
name class๋ฅผ ๊ฐ์ง ๋์์ ์์ฑ์ ์ฒ๋ฆฌ
import './main.css';
import {createApp} from 'vue'
import App from '~/App'
//์ ์ญ๋ฑ๋ก
import Btn from '~/component/Btn'
const app = createApp(App)
app.component('Btn',Btn)
app.mount('#app')
์ฃผ์๋ด์ฉ๋ค์ด ๋ด์์ค๋ ๊ณณ์ผ๋ก
css๋ ์ฒ๋ฆฌํ๊ณ vue์ App๋ฐ App์ ๋ด์ Btn๋ ์กด์ฌํ๋ค.
<template>
<div
class="name"
@click="updateName"
>
{{ name }}
</div>
<Btn></Btn>
</template>
<script>
import {ref} from 'vue';
export default{
setup(){
const name = ref('Kossie Coder1');
const updateName = () => {
name.value = 'Kossie Coder'
}
return {
name,
updateName
}
}
}
</script>
Kossie Coder1์ด ์ฒ์ ์ถ๋ ฅ๋๋ฉด์ ํด๋ฆญ์ Kossie Code๋ก ๋ฐ๋๋ ์ญํ ์ ํ๋ค.
Btn ๋ฒํผ์ด ์ถ๊ฐ๋๊ฒ ๋ง๋๋ ์ญํ
<template>
<button @click="log">
Click me!
</button>
</template>
<script>
export default {
methods:{
log(){
console.log('Click')
}
}
}
</script>
click ๋ฒํผ์ ๋๋ฅด๋ฉด ์ฝ์์ ์ถ๋ ฅํ๋ ์ญํ
"scripts": {
"build": "cross-env NODE_ENV=production webpack --progress",
"start": "webpack serve --progress"
}
๊ฐ๋ฐ ํ๊ฒฝ ์คํ
์๋ฒ์ ์ ๋ก๋ํ ํด๋์์ ํ์ผ ์์ฑ
๊ฒฐ๊ณผ๋ npm run dev์ ๊ฐ๋ค
module
ํ์ผ์ ํด์ํ๊ณ ๋ณํํ๋ ๊ณผ์ ์ ๊ด์ฌํ์ฌ ๋ชจ๋์ ์ฒ๋ฆฌ
plugin
๋ฒ๋ค๋ ๊ฒฐ๊ณผ๋ฌผ์ ์ฒ๋ฆฌ
ex) ๋ฒ๋ค๋ js๋ฅผ ๋๋ ํ ํ๊ฑฐ๋ ํน์ ํ ์คํธ๋ฅผ ์ถ์ถํ๋ ์ฉ๋ ๋ฑ
ํด๋น ๊ฒฐ๊ณผ๋ฌผ์ ํํ๋ฅผ ๋ฐ๊พธ๋ ์ญํ ์ ํ๋ฏ๋ก ๋ฒ๋ค๋ง๋ ํ์ผ์ ์ฒ๋ฆฌ
babel์ ํตํด ๋ง๋ค์ด์ง js๋
require
๋ฅผ ์ด์ฉํ์ฌ ๋ธ๋ผ์ฐ์ ์์ ์ ์ฉ๋ ์ ์๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด์ webpack์ ์ค์นํ๊ณ webpack์ babel-loaderํ ํ ๊ฐ๋ฐ์๋ฒ๋ก ์ฒ๋ฆฌํ๊ฑฐ๋ ๋ฒ๋ค๋ฌ๋ก build๋ฅผ ํ์ฌ ๋ธ๋ผ์ฐ์ ์์ ๋์ํ๊ฒ ๋ง๋๋ ์ญํ ์ webpack์ด ๋ด๋นํ๋ค.