major.minor.patch
node.js
는 JS가 동작할수 있게 해주는 환경. 브라우저가 없어도 돌아감.
Npm
은 node package manager
의 약어. JS로 만들어진 패키지들을 관리함.
html 다 읽고나서 스크립트 실행하라고 body
맨 아래 적는데, 이렇게 하지말고
헤더 안에 선언 후 defer
키워드 붙여줌.
<script defer src="./main.js"></script>
async
키워드도 비슷한 역할(백그라운드에서 스크립트 다운로드 후 html파싱되면 실행)하지만
여러 script
태그를 불러올때 순서를 보장하진 않는다.
개발단계에서만 의존하는 패키지를 설치할때 사용하는 수식어
--save-d
와 같은 말이다.
이렇게 캐럿^
기호가 있을땐 그 이상 버전을 아우를 수 있다는 의미다.
=> 환경이 다르면 패키지 버전 차이가 날수있음. 예측하지 못하는 이슈가 발생함. 이를 방지하기 위한게 package-lock.json
즉, package-lock.json은 설치할때의 정확한 버전을 갖고
package.json은 설치할때의 버전의 범위를 갖고있음.
=> 커밋할때 lock
파일도 같이해주자~
노드환경에서 내보내는 방식. commonJS
방식이라 부른다
가져올땐 require
로 가져옴.
JS에서사용하는 import,export
는 ESModule
방식
Single File Component.
html, css, js를 한 파일에 작성할 수 있는 Vue의 기능이다.
file.vue
확장자로 만들고 사용함.
하지만 브라우저는 vue
파일을 바로 읽지못함. 브라우저가 인식할 수 있게 번들링하는 과정이 필요하다.웹팩을 사용해도 좋지만, 먼저 parcel을 사용하여 번들링 해보자
npm i -D parcel
로 개발단계의존성으로 설치하고
"scripts": {
"dev": "parcel ./src/index.html"
},
npm run dev
실행하면...
어랍쇼
rm -r .parcel-cache
명령어로 캐시날려주고다시해봄
잘보이는구먼 굳!
distribute의 약자 dist.
parcel이 잘 번들링 해주었다.
배포할때 이 폴더를 이용해주면 된다.
"scripts": {
"dev": "parcel ./src/index.html",
"build": "parcel build ./src/index.html"
},
요래요래 추가해주고 npm run build
해주면..
오류가 난다.
package.json
의 main
을 지워주어야함.
=> main은 패키지의 진입점이 되는 모듈인데, 우리는 패키지를 만드는 게 아니라 웹을 만드는거니까 지워주어도 됨.
기존과 다르게 파일이 조금 더 추가되었다.
세세한 조정이 불가능. 쉽고 빠르게 번들링이 가능하다.
=> 초기단계에서 빠르게 만들때 사용 가능. 공부할때도 하면 좋을것 같다.
<script setup>
import { ref } from 'vue'
const greeting = ref('Hello World!')
</script>
<template>
<p class="greeting">{{ greeting }}</p>
</template>
<style>
.greeting {
color: red;
font-weight: bold;
}
</style>
공식문서에 나와있는 예제. 즉 Html, Css, Js를 한군데 묶어서 관리하는 것이다.
왜 사용할까?
정리하자면
1. 한군데 몰아서 작성해서 편하고 컴파일을 한번에 해서 런타임시 컴파일 시간 최적화
2. 자동완성검사할때 편리
3. 컴포넌트마다 스타일 적용할수 있어서 편리
나머지는 공부해가며 천천히 이해해보자.
기본적인 html-css-js구조처럼 생겨서 리액트보단 익숙하구먼
저번에 한번 사용해보긴했는데, 상세하게 알진 못하고 사용함.
이번에 잘 알아보자.
웹팩도 번들러다.
번들은 파일을 압축해주어 용량도 줄이고 http통신 횟수를 줄이는 게 주 목적. 컴파일은 번들러가 해주는 일이 아니니까 구분하자.
parcel은 그냥 빌드명령어 사용하면 빌드해주고 뚝딱 빌드된 파일이 dist
에 저장되었다.
웹팩은 설정이 좀 필요하다.
//node.js의 내장모듈경로를 해석해준다
const path = require('path');
module.exports = {
//메인이되는 js파일(모듈 번들링 시작 진입점)
entry: './src/index.js',
//빌드된 파일이 생성될 경로와 이름
output:{
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
}
이렇게 설정한 파일을 웹팩이 읽어서 적용해준다.
참고로 path.resolve()
는 무조건 입력해주는 게 좋다.
=> 웹팩 설정코드가 늘어나다보면 webpack.config.js
를 기준으로 경로가 설정되는게 아닐 확률이 높음. 따라서 경로를 확실하게 정해준다.
npm i -D webpack webpack-cli
으로 웹팩과 커맨드라인 인터페이스까지 설치해줌. 터미널에서 웹팩을 조종할수 있게 해주는 패키지다.
웹팩은 JS파일만 해석 가능하다. .vue처럼 다른 파일을 해석하려면 로더라는 기능을 웹팩에 추가해야함.
//webpack.config.js
output...,
module: {
rules: [
{
test: /\.vue$/,
use: "vue-loader",
},
],
},
정규식으로 .vue
로 끝나는 파일을 모조리 vue-loader의 도움을 받아 웹팩으로 번들링 하겠다는 의미다.
그리고 vue-loader는 뷰=>JS로 컴파일하는 기능이 따로 없다. 따라서 @vue/compiler-sfc패키지도 설치해주어야함.
참고로 컴파일러와 뷰는 버전이 일치해야함!
또한 플러그인도 등록해주어야한다.
//webpack.config.js
const { VueLoaderPlugin } = require("vue-loader");
...
module...,
plugins: [new VueLoaderPlugin()],
이렇게 하고 npm run build
를 하면...
빌드가 잘 되었다. 하지만 웹팩으로 번들링할땐 모드를 명시해주어야한다.(개발, 프로덕트)
빌드된 결과를 보자
js는 잘 되었는데, html파일이 없다!dist
폴더에 어떻게 넣어주지?
바로바로...html-webpack-plugin을 사용하면된다.
점점 뭐가 추가되는구먼..
//webpack.config.js
const HtmlPlugin = require("html-webpack-plugin");
...
plugins: [
new VueLoaderPlugin(),
new HtmlPlugin({
//html파일 경로를 지정.
//html-webpack-plugin은 내부적으로 path.resolve기능 내장되어있음.
template: "src/index.html",
}),
],
다시 npm run build
명령어를 사용하면!
따란~
참고로 원본 html
파일에 srciprt
태그가 없더라도, 웹팩이 entry
를 이용해 경로를 추가해준다!
다만 dist
폴더에 사용자가 직접 필요없는 파일을 만들더라도 그냥 남아있음.
이때 웹팩 설정에서 clean
추가해주면됨ㅎㅎ
//webpack.config.js
output: {
path: path.resolve(__dirname, "dist"),
clean: true,
},
개발서버를 오픈할수 있는 패키지. 패키지를 설치한 뒤
//package.json
"scripts": {
"dev": "webpack-dev-server --mode development",
"build": "webpack --mode production"
},
이렇게 명령어를 추가해 준뒤 실행해보자!
잘나오는구먼? 참고로 webpack-dev-server를 이용하면 파일 수정사항이 실시간 반영된다!
참고로 웹팩 설정을 바꾸면 서버를 재시작 해주어야함ㅎㅎ
아까도 말했듯 웹팩은 js만 인식함. 따라서 CSS도 같이 넘겨주려면...이제 알겠지?
//webpack.config.js
...module
{
test: /\.css$/,
use: ["vue-style-loader", "css-loader"],
},
배열에 추가할땐 순서가 중요하다. 먼저 해석되어야하는 로더를 제일 나중에작성.
컴포넌트 내부 스타일이 컴파일되면 전역으로 설정됨. 이때 scoped
키워드를 스타일 태그에 추가하면, 컴포넌트에만 적용된다.
<style scoped>...</style>
유니크한 id로 스타일이 적용된 노드를 구분짓나보다!
SCSS로 스타일을 작성할 수도 있다. 하지만 로더가 또 필요함!
sass sass-loader
를 설치하고...
설정을 요래요래...
//webpack.config.js
{
test: /\.s?css$/,
use: ["vue-style-loader", "css-loader", "sass-loader"],
},
정규식도 잘다뤄야겠구나...!?
<template>
<h1>{{ msg }}</h1>
<Hello />
</template>
<script>
import Hello from "./components/Hello.vue"
export default{
components:{
Hello
},
data(){
return{
msg:"hi webpack!"
}
}
}
</script>
<style>
h1{
color:blue;
}
</style>
지금 Hello
라는 컴포넌트를 가져올때 상대경로로 가져오고잇다. 파일 간 오류가 생길 가능성이 있어서 절대경로로 사용하는 게 권장됨. 이를 위해 웹팩의 경로별칭기능 활용하면 됨.
//webpack.config.js
...
resolve: {
//확장자 사용하지 않아도 읽어올수 있게.
extensions: [".vue", ".js"],
//경로 별칭!
alias: {
"~": path.resolve(__dirname, "src"),
},
},
entry: "./src/main.js",
결과는 이렇다
//변경전
import Hello from "./components/Hello.vue"
//변경후
import Hello from "~/components/Hello"
favicon이나 기타 파일을 dist에 넣어야될때가 있음. 그때 사용하는 패키지가 copy-webpack-plugin
const CopyPlugin = require("copy-webpack-plugin");
...
plugins: [
...
new CopyPlugin({
patterns: [{
from: "static"
//to는 output을 참조하기에 생략해도 됨.
//to: "dist",
}],
}),
static폴더에 있던 favicon이 잘넘어왔다 ㅎㅎ
node_modules/
dist/
.vsocde/ (vsocde 설정파일)
굳!
vue에서 사용하려면 eslint eslint-plugin-vue
설치!
이후 .eslint.js파일만들고...익스텐션설치하고..
다양한 옵션들이 있으니 하나하나 다 따져서 써보는건 의미가 없고! 저번에도 사용해봤고!
필요할때 한번에 쫙 넣어서 사용하겠다!
Vue가 컴포넌트를 발견하면 구현할 수 있게 위치를 등록해주어야함.
//main.js
import * as Vue from "vue";
import App from "~/App";
import Btn from "~/components/Btn";
const { createApp } = Vue;
const app = createApp(App);
app.component("Btn", Btn);
app.mount("#app");
createApp().component("사용자 지정 이름", 컴포넌트)
이렇게 하면 어떤 컴포넌트에서든 사용할 수 있는 전역컴포넌트가 된다.
<template>
<h1>Hello vue !</h1>
<Btn></Btn>
</template>
<script>
export default{
}
</script>
import하지않아도 사용할 수 있음.
다만 전역 컴포넌트는 트리 쉐이킹(사용하지 않는 코드 제거)등의 번들링 기능을 활용할 수 없다.
또한 의존관계를 명시적으로 만들지 못함.
=> 최대한 전역 컴포넌트 사용을 줄인다. 자주 사용하는 버튼컴포넌트 같은 경우에는 전역으로 사용하기도 함
import
키워드로 갖고와서 components
옵션에 등록.
<template>
<h1>Hello vue !</h1>
<Btn></Btn>
<Hello/>
</template>
<script>
import Hello from '~/components/Hello';
export default{
components:{
Hello
}
}
</script>
지금까지 사용한 방식이 지역컴포넌트다.
원시값들은 기냥 전달해주면 되는데, 객체전달할때는 프로퍼티 별로 전달하지 않고 한번에 전달하는 방법도 있다.
post:{
id:1,
title:"나 제목이오"
}
<blog-post v-bind="post"></blog-post>
<!-- 위, 아래 둘 다 같은 의미다 -->
<blog-post :id="post.id" :title="post.title"></blog-post>
MVVM패턴. 뷰와 100%일치하지는 않는다
이렇게 생겼지만, 모든 props는 부모=>자식 단방향 바인딩을 형성한다. 그래서 readonly
가 되어있음.
그라믄 바꿔서 사용하려면 어떡해야하나?
computed
속성 정의해두고 쓰기간단하구먼?
props:{
message:String,
name:[String,Number],
email:{
required:true
type:String,
default:"디폴트 이메일값"
},
},
props2:{
validator: function(value){
//값이 꼭 아래 배열과 일치해야함
return['a', 'b'].indexOf(value) !== -1
}
프롭스로 받아올때 타입을 지정해줄수 있다. 신기허구먼?
참고로 배열은 유니온타입(or)과 똑같다.
default
는 기본값을 설정하고 프롭스를 덮어쓴다.(참조형 데이터로 들어오면 함수로 리턴해주어야함) required
는 무조건 있어야 하는 값.
이거 완전 mongodb스키마와 비슷하구먼
HTML속성명은 대소문작 구분없이 소문자로 해석
=> html속성으로 작성할땐 케밥-케이스로 해야함.
<a v-bind:post-title></a>
<script>
...
data(){
return{
postTitle:....
}
}
</script>
컴포넌트 내부 요소가 여러개일땐 그냥 class="name"
이런식으로 할당할 수 없음
<!-- Hello.uve -->
<template>
<h1
:style="$attrs.style"
:class="$attrs.class">hello</h1>
<h2 @click="$attrs.onClick">dsadasd</h2>
</template>
<!-- App.vue -->
<template>
<h1>{{ msg }}</h1>
<Hello @click="msg += '!' " style="font-size: 100px" class="hello"/>
</template>
요래요래 따로 전달 가능하다. 여기서 $attrs
는 뭘까?
=> props
로 전달한 값을 제외한 객체!
이를 Non-prop 속성이라함.
또한 inheritAttrs:false
옵션을 script내부에 적어주면 프롭스를 제외한 값을 가져오지 않는다.
양이 굉장히 많은듯 싶다가도 이해가 잘 되었다.
프롭스가 단방향이라는게 아주 맘에들었다. 자식이 바꿔버리면 예측 불가능한 사이드이펙트가 자주 발생할것같음.
리액트를 아주 조금 해본 경험 + 노션클론 리팩토링을 진행하며 얻은 경험(이게 아주 값진것 같음)이 도와주지 않았나 싶다.
물론 지금JS를 사용할때처럼 능숙하려면 시간이 걸리겠지만...이전보다 학습속도가 빨라진건 좋은 징조다
뷰가 쉬워서 그런걸 수도 있음..!😯
다만 웹팩,린트 부분은 중요한 설정은 알아놔야할것 같다. 다 외우는건 비효율적이고...
아 왜이리 패키지가 많이 필요하지..?ㅋㅋㅋㅋ