728x90

Option API

export default{
  data(){
    return{
    
    }
  },
  methods:{
  
  },
  computed:{
  
  },
  mounted(){
  
  }
}
  • 같은 종류의 일을 한다고 하더라고 코드가 data, mothods, computed, mounted에 떨어져 있을 수 있다. 즉, 응집성이 떨어진다

Composition API

export default{
  setup(){
    //data
    
    //methods
    
    //computed
    
    //lifecycle hooks
  }
}
  • 비즈니스 로직과 데이터를 setup() 이라는 함수에서 통합 관리할 수 있다. 응집성이 올라간다.

setup

  • 복잡한 로직에서 사용. react의 custom hook와 비슷하다.
<template>
<div  class="home">
  home
  <p ref="p"> My name is {{name}} and age is {{age}} </p>
  <button @click="handleClick">click me</button>
</div>

</template>

<script>
import {ref} from 'vue';

export default{
  setup(){
    console.log('set up');
  
    const p = ref(null);
  
    let name = 'mario';
    let age = 30;
  
    const handleClick = () =>{
      p.value.classList.add('test');
      p.value.textContext = 'hello';
    }
  
    return{
      name,
      age,
      p,
      handleClick,
    }
  }
}
</script>
  • created() 보다 먼저 실행된다
  • 반환 데이터 reactive하게 변경하는 방법
    1. ref 사용. 변수를 ref를 이용하여 선언하면 reactive 해진다. 해당 변수값 참조시 setup() 내에서는 .value를 붙이고 바깥에서는 해당 변수명을 그대로 참조하면된다.
      • <template>
        <div  class="home">
          home
          <p ref="p"> My name is {{name}} and age is {{age}} </p>
          <button @click="handleClick">click me</button>
        </div>
        
        </template>
        
        <script>
        import {ref} from 'vue';
        
        export default{
          setup(){
          
            let name = ref('mario'); // ref 내부 값은 초기값을 의미한다
            let age = ref(30);
          
            const handleClick = () =>{
              name.value = 'luigi';
              age.value = 35;
            }
          
            return{
              name,
              age,
              handleClick,
            }
          }
        }
        </script>
    2. reactive사용. 변수를 reactive를 이용하여 선언하면 reactive해진다. ref와 사용법은 유사하지만 setup()내에서 .value를 이용하지 않고도 변수값을 참조할 수 있다는점, primitive type이 초기값으로 주어져서는 안된다는 점이 유일하게 다르다
      • <template>
        <div  class="home">
          home
          <p ref="p"> My name is {{ninja.name}} and age is {{ninja.age}} </p>
          <button @click="handleClick">click me</button>
        </div>
        
        </template>
        
        <script>
        import {reactive} from 'vue';
        
        export default{
          setup(){
          
            const ninja = reactive({name:'mario',age:30});
          
            const updateNinja = () =>{
              ninjaOne.age=40;
            }
          
            return{
              ninja,
              updateNinja,
            }
          }
        }
        </script>
  • 내부에서 computed를 사용할 수 있다.
    • <template>
      <div  class="home">
        <input type="text" v-model=search/>
        <ul v-for="name in names" :key="name">
          <li>{{name}}</li>
        </ul>
      </div>
      
      </template>
      
      <script>
      import {computed,ref} from 'vue';
      
      export default{
        setup(){
          
          const search = ref('');
          const names = ['mario','yoshi','luigi','toad','bowser','koopa','peach'];
          
          const filteredNames = computed(()=>{
            return names.filter((name)=>name.includes(search.value));
          })
          
          return{
            search,
            names:filteredNames
          }
        }
      }
      </script>
  • watch, watchEffect를 사용할 수 있다.
    • watch: Vue2에서 일반적으로 사용하던 watch와 동일. observe할 value를 등록후 해당 값이 변경되면 callback함수 실행
    • watchEffect: callback 함수 내부 변수의 dependency를 찾아 해당 dependency 변수값이 변경되면 callback함수가 자동으로 실행된다. watchEffect 의 반환값을 대입 받은 변수를 실행하면 watchEffect는 destroy된다.
    • // 다음은 search 값이 변경되면 자동으로 watch, watchEffect의 callback 함수를 실행하게 만든 코드이다.
      // handleClick 실행시 watch와 watchEffect는 메모리를 반환한다.
      <script>
      import {watch,watchEffect,ref} from 'vue';
      
      export default{
        setup(){
          
          const search = ref('');
          const names = ['mario','yoshi','luigi','toad','bowser','koopa','peach'];
          
          const stopWatch = watch(search,()=>{
            console.log('watch function ran');
          })
          
          const stopEffect = watchEffect(()=>{
            console.log('watchEffect function ran',search.value);
          })
          
          const handleClick = ()=>{
            stopWatch();
            stopEffect();
          }
          
          return{
            search,
          }
        }
      }
      </script>
  • props를 받을 수 있다.
    • // PostList.vue
      // posts props가 넘어온 상황
      <script>
      export default{
        props: ["posts"], //props를 선언해줘야한다.
        setup(props){
          console.log(props.posts)
        }
      }
      </script>
  • vue lifecycle을 이용할 수 있다. setup 밖의 동일한 lifecycle보다 먼저 실행된다.
    • <script>
      export default{
        setup(props){
          onMounted(()=>console.log("component Mounted"));
          onUnMounted(()=>console.log("component UnMounted"));
          onUpdated(()=>console.log("component Updated"));
        }
      }
      </script>

componentAPI에서 data fetch

setup()에 async를 선언않고 setup() 내부에 async function을 생성해 이를 호출한다.

<template>
  <div class="Home">
    <div v-if="error">{{error}}</div>
    <div v-if="posts.length">
      <PostList :posts="posts"/>
    </div>
    <div v-else>
      Loading...
    </div>
  </div>
</template>

<script>
import {ref} from 'vue'
export default{
  setup(){
    const posts= ref([]);
    const error = ref(null);
    
    const load = async() =>{
      try{
        let data = await fetch('asdf');
        if(!data.ok){
          throw new Error('no data available'
        }
        posts.value = await data.json(); 
      }catch(e){
        error.value = e.message;
        console.log(error.value);
      }
    }
  }
}
</script>

Reusable Composables

여러 컴포넌트에서 같은 로직의 setup()을 사용할 경우 코드를 반복해서 사용하는것은 비효율적이다.

다른 파일로 떼어놓고 필요할때마다 호출하여 사용할 수 있다.

//composables/getPosts.js
import {ref} from 'vue';

const getPosts = () =>{
  const posts = ref([]);
  const error = ref(null);
  
  const load = async()=>{
    try{
      let data = fetch('asdf')
      if(!data.ok){
        throw new Error('no data available');
      }
      posts.value = await data.json();
    }catch(e){
      error.value = e.message;
      console.error(error.value);
    }
  }
  //load(); //넣지않는다
  
  return {posts,error,load}
}

export default getPosts;
//Home.vue
<script>
export default{
  import getPosts from '../composables/getPosts'
  setup(){
    const {posts,error,load} = getPosts(); // 처음에 posts와 error은 비어있는 상태. 뒤에 load가 호출되면 값이 채워진다.
    load() // getPosts에 집어넣지 않는다.
    return {posts,error}
  }
}
</script>

Vue3 + Typescript 설정 방법

npm install -g @vue/cli

 

vue --version 4.5.8

 

vue create vue-3-and-typescript

 

Babel

Typescript

3.x

 

no class style component

 

eslint+prettier

 

lint on save

 

구조

main.ts : equivalent to main.js

shims-vue.d.ts : Helper file for Typescript. No need to modify it. give better definition showing what's going on vue files

tsconfig.json : configure options for ts compiler

 

add ts to existing vue 3 project

vue add typescript -> vue/cli upgrade

use class-style component syntax ? no

use babel alongside typescript? yes

convert all .js files to .ts ? yes

skip type checking of all declaration files ? yes

 

 

# creating components with Typescript

<script lang="ts">

import {defineComponent } from 'vue' : import Vue helper function

define component that works well with typescript

single file component에 설정할 것 전부이다.

 

# Type Fundamentals

Common Javascript types often encountered : String, Number, Boolean, Array, Function, Object

Typescript provides additional types to Javascript 

- Any : essentially disables any type checking

- Tuple : fixed length arrays with predefined data types

- Enum : allows you to define friendly names to a set of values

enum ArrowKeys {

  Up, // 1

  Down, //2

  Left= 0 , // 0

  Right = 5 //4

}

등등 더있음

 

Object 타입 정의방법

let person : {

  name : string

  age : number;

  activeAvenger: boolean;

  powers : string[];

} = {

  name: 'Peter Parker',

  age: 20,

  activeAvenger : true,

  powers: ['wall-crawl', 'spider-sense']

}

 

Limitaions of Predefined Types

 

The need for custom types is a common one. -> Type and Interface

 

What is Type

Type allows you to define alias how the data should be shaped.

 

type buttonType = 'primary' | 'secondary' | 'success' | 'danger'

let buttonStyles: buttonType = 'primary' // O

let buttonStyles : buttonType = 'error' // X

 

What is Interface

type for object

 

interface Hero {

  name : string;

  age : number;

  activeAvenger : boolean;

  powers : string[];

  universe : ComicUniverse; // type ComicUniverse = 'Marvel' | 'DC'

}

 

let person:Hero = {

  name: 'Peter Parker',

  age: 20,

  activeAvenger : true,

  powers: ['wall-crawl', 'spider-sense'],

  universe : 'Marvel'

}

 

Use Type except for an Object

 

# Data With Custom Types

Install VSCode extension VueDX : provide edtior service

 

src 폴더 밑에 types.ts 생성

export interface EventItem {

 id : number

 category : string

 title : string

 description : string

 location: string

 date: string

 time: string

 organizer: string

}

 

//Eventdetail.vue

import {EventItem} from '../types'

 

data(){

  event : {} as EventItem // Type Assertion

}

 

# Props With Types

 

import {EventItem, PropType} from '../types' // PropType: helper method

 

props : {

  event: {

   type: Object as PropType<EventItem>, // type : EventItem , type : Object as EventItem쓰면 에러뜬다. Props에서는 Vue에서 지정한 방법으로 타입을 지정해야한다

   required: true

  }

}

 

What is Generic?

function createList (item: number) : number[]{ // createNumberList가 아니야 reusable하게 다른 타입에서도 작동하게 만들자 => Generic

 const newList : number[] = [];

 newList.push(item);

 return newList;

}

 

const numberList = createList(123);

 

Generic은 함수에서 사용되는 변수의  type을 Dynamic하게 정의할 수 있도록 해준다

function createList<CustomType>(item: CustomType) : CustomType[]{

  const newList: CustomType[] = [];

  newList.push(item);

  return newList;

}

const numberList = createList<number>(123)

const stringList = createList<string>("Hello");

 

# Custom Methods with CustomTypes

 

1. Computed

For computed properties, focus on what type is returned

 

data(){

  return {

   events: [] as EventItem[]

  }

},

computed:{

  firstEvent(): EventItem {

   return this.events[0]

  }

}

 

2. Methods

For methods, add types for the parameters and return value if applicable

 

data(){

  return {

   events: [] as EventItem[]

  }

},

methods:{

  addEvent(newEvent: EventItem) {

   this.events.push(newEvent)

  },

  secondEvent(): EventItem{

   return this.events[1]

  }

}

 

# Composition API with Typescript

data: () => ({

  newTask : {

   label: '',

   type: 'personal',

  } as TodoItem,

  taskItems: [] as TodoItem[],

  listFilter: 'all'

}),

computed: {

  filteredTasks() : TodoItem[] {

   if(this.listFilter == 'complete'){

    return this.taskItems.filter((item:TodoItem) => item.isComplete === true)

   }else if(this.listFilter === 'incomplete'){

    return this.taskItems.filter((item.TodoItem)=>item.isComplete === false)

   }else{

     return this.taskItems

   }

  }

},

methos:{

  addTask() {

   this.taskItems.push({

     ...this.newTask,

     isComplete:false

   })

  }

}

 

Refactor this in composition api

 

setup(){

  const state = reactive({

  newTask : {

   label: '',

   type: 'personal',

  } as TodoItem,

  taskItems: [] as TodoItem[],

  listFilter: 'all'

});

 

  const filteredTasks = computed(()=> { // computed 내부의 return 타입을 보고 타입추론을 해준다

   if(state.listFilter == 'complete'){

    return state.taskItems.filter((item:TodoItem) => item.isComplete === true)

   }else if(state.listFilter === 'incomplete'){

    return state.taskItems.filter((item.TodoItem)=>item.isComplete === false)

   }else{

     return state.taskItems

   }

  })

 

  const addTask = ()=> {

   this.taskItems.push({

     ...this.newTask,

     isComplete:false

   })

  }

  return {

    ...toRefs(state),

    addTask, 

    filteredTasks

  }

 

}

'VueJS' 카테고리의 다른 글

Vue3 - 3.Type Fundamentals  (0) 2021.12.28
Vue3 - 2. Vue3 + Typescript  (0) 2021.12.28
vue3 - 0.주요 특징  (0) 2021.12.10
array / object prototype  (0) 2021.06.27
VueJs Project Architecture  (0) 2021.01.28
728x90

Vue3의 새로운 기능

Composition API

  • 재사용성, 구성과 가독성을 향상시켜준다
  • setup()

Multiple Root Element

  • 하나의 컴포넌트 안에서 여러개의 root element를 가질 수 있다.
    •  
    • <template> <div> <p>Hello, World</p> </div> <div> <p>Hello, World!!</p> </div> </template>

Teleport Component

  • 특정 컴포넌트를 DOM의 다른 위치에 렌더링 시켜준다. (React에서 Portal)
  • modal에서 사용하기 좋음
  • <!-- App.vue -->
    <teleport to=".modal"> <!-- #app style 영향을 안받는다 -->
      <modal>
        <template v-slot:header><h1>haha header</h1></template>
        <template v-slot:content>this is content</template>
      </modal>
    </teleport>

Suspense Component

  • 비동기 컴포넌트를 다루기위해 사용
  • 데이터 로딩이 끝날때까지 spinner와 같은 fallback component를 보여주는데 사용하기 좋음

Typescript Support

  • Vue application에서 Typescript를 쓸수있다. (Vue2에서는 어려웠음)

 

Vue3 시작하기

  1. node 설치
  2. vue/cli 설치
    •  
    • npm install -g @vue/cli​
  3. 프로젝트 생성
    • vue create 프로젝트명​
      
      //Manually select features
      //Choose Vue Version, Babel
      // 3.x
      //N

 

 

'VueJS' 카테고리의 다른 글

Vue3 - 3.Type Fundamentals  (0) 2021.12.28
Vue3 - 2. Vue3 + Typescript  (0) 2021.12.28
Vue3 - 1. Composition API  (0) 2021.12.11
array / object prototype  (0) 2021.06.27
VueJs Project Architecture  (0) 2021.01.28
728x90
  • 모던 웹 브라우저(크롬, 사파리, 엣지 등)에서 크로스 브라우징이 가능해야 한다.

크로스 브라우징이란?

- 어떤 환경에서 접근하여도 동등하게 작동되는것을 의미.

  - 브라우저나 OS마다 보여지는 모습이 다른 경우가 많은데, 여러 환경에 호환성을 유지할 수 있도록 한다.

 

크로스 브라우징 작업이 필요한 원인은 무엇일까?

- 브라우저마다 랜더링 엔진이 다르기 때문

  - 작동되지 않는 HTML5, Javascript 코드가 존재

  - 해석하지 못하는 CSS 코드 존재

  - 브라우저 버그들이 존재

  - 브라우저마다 자체적인 CSS 스타일

 

크로스 브라우징을 하는 방법

- 수동

- 크로스 브라우징을 하는 방법으로 가장 좋은 방법으로는 각 브라우저를 직접 들어가는 방법이다.

- 체크목록

  - 크롬

  - 웨일

  - IE

  - FireFox

  - Edge

  - Opera

  - Safari

-자동

- 셀레니엄 같은 자동화 도구를 사용하여 전문 QA가 작성한 스크립트로 다양한 브라우저에서 테스트 시나리오를 실행할 수 있다.

 

 

바벨 (for script)

- 크로스 브라우징 이슈를 해결하기 위해 생겨난 툴이 바벨이다. ES6+ 버전의 자바스크립트나 타입스크립트, JSX등 다른 언어로 분류되는 언어들에 대해서도 모든 브라우저에서 동작할 수 있도록 호환성을 지켜준다.

 

'browser' 카테고리의 다른 글

자바스크립트 엔진(인터프리터)  (0) 2021.07.14
브라우저 렌더링  (0) 2021.07.14
Local Storage vs Session Storage vs Cookies  (0) 2020.11.24
728x90

이미지의 width, height와 같은 정보는 이미지 load이전에 알 수 없다. (로드전에 값 할당은 할 수 있다.)

onload가 되고나서야 값을 가져올 수 있는데 이렇게 onload이후에 값을 가져오는 방법은 다음과 같다.

See the Pen by korkt-kim (@korkt-kim) on CodePen.

'Javascript' 카테고리의 다른 글

Image Lazy Loading  (0) 2021.07.24
prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20
728x90

Package-lock.json 이 생성되는 이유

Package.json에서 Dependency versioning을 할때 명확히 버전을 명시 해주지 않을때가 있기때문에 생성된다.

Package.json의 Dependencies의 역할은 패키지들의 릴리즈 버전 추적 및 해당 버전 install에 있다.

즉, 서로 다른 환경에서 package를 설치할때 패키지들이 sementic versioning을 명확히 지키더라도 다른 package를 설치하면서 하위호환이 안맞는 경우가 생길 수 있다. (버전이 올라가면서 특정 모듈 함수가 deprecated되었을때가 대표적)

 

이런 상황을 해결하기 위해 필요한 파일이 바로 package-lock.json 이다. package.json에는 모호하게 적혀있던 package 버전이 package-lock.json에는 설치되어야 할 버전이 명확히 명시되어있다.

 

 

package-lock.json이 존재할 때 npm install을 실행할 시 더 이상 package.json을 참조하지않고 해당 package-lock.json 파일을 참조하여 package를 설치한다.

 

 

 

 

https://junwoo45.github.io/2019-10-02-package-lock/

'Webpack' 카테고리의 다른 글

Package.json dependencies versioning  (0) 2021.07.27
Bundle Diet  (0) 2021.07.26
Webpack 이란?  (0) 2021.01.15
728x90

Semeantic Versioning(SemVer. 유의적 버전)

버전 번호를 어떻게 정하고 올려야 하는지를 명시하는 규칙과 요구사항을 제안한다.

공개 API를 정의하고, 버전 번호를 올리는 방식을 통해 API가 어떻게 바뀌는지 표현한다.

버전을 X.Y.Z (주.부.수) 형식으로 정한다. (Major,Minor,Patch)

API에 영향이 없는 버그 수정은 수(修)버전을 올리고, API가 호환되면서 바꾸거나 추가하는 경우에는 부(部)버전을 올리고, API가 호환되지 않는 변경이라면 주(主)버전을 올린다.

 

Dependency Versioning

Package.json의 Dependency들의 versioning은 위의 SemVer의 규칙을 따른다.

  • 1.2.3 : v1.2.3 과 일치해야한다.
  • >1.2.3 : v1.2.3보다 높아야한다. 만약 v1.2.4가 없다면 v1.2.5를 찾고 v1.2.5도 없다면 v1.2.6을 찾는 방식.
  • >=1.2.3 : v1.2.3보다 같거나 높아야한다.
  • <1.2.3 : v1.2.3보다 낮아야한다.
  • <=1.2.3 : v1.2.3보다 같거나 낮아야한다.
  • ~1.2.3 : v1.2.3과 가장 가까운 버전
    • 현재 지정한 버전의 마지막 자리(수) 내의 범위에서 자동 업데이트한다.
    • 위의 상황은 1.2.3<= x < 1.3.0 중 가장 1.2.3과 가까운 버전
  • ^1.2.3 : v1.2.3과 호환이 되는 버전
    • api의 주버전이 바뀌면 API의 호환성이 깨지게되고 부,수 버전은 하위호환성을 지킨다는 SemVer의 특성을 지키고 있다는 가정하에 사용한다 .
    • 현재 지정한 버전의 첫번째 자리 (주) 내의 범위에서 자동 업데이트한다. 
    • 위의 상황은 1.2.3 <= x < 2.0.0 중 가장 최신버전

'Webpack' 카테고리의 다른 글

Package-lock.json  (0) 2021.07.27
Bundle Diet  (0) 2021.07.26
Webpack 이란?  (0) 2021.01.15
728x90

Browser에서 Javascript 파일 실행과정

 

같은 용량이더라도 이미지는 파일을 다운로드한 후 디코딩만 하면되지만 JS를 실행하기위해서는 위와같이 작업단계가 많으므로 JS 실행이 이미지 로딩보다 오래걸리게된다.

브라우저에서 JS실행을 최적화 하기위해서 번들 최적화는 매우 중요하다.

 

1. 원인 찾기

Webpack을 기준으로 Bundle 분석 도구로는 Webpack Analyse, Webpack Visualizer, Webpack Bundle Analyzer 3개가 있다.

Webpack Bundle Analyzer가 용량별로 시각화를 해주기때문에 어떤 라이브러리가 많이 사용되고 있는지 알 수있고 사이드바를 이용해 검색과 필터링도 가능하다사용하기 쉽고 기능이 좋다.

같은 라이브러리이지만 버전이 다른경우

  • npm이 dependency conflict를 해결하는 특성때문이다. npm은 라이브러리간 관계를 검색하고 필요한 라이브러리를 다운받는다. 이 때 dependency가 같은 라이브러리를 참조하지만 이 라이브러리의 버전이 다르다면 해당 버전을 모두 설치한다. 각 library별로 가상 환경의 node_modules를 이용하기 때문에 충돌이 없다. 
    • browserfy는 직접 사용자에게 어떤 버전을 설치할지 물어본다.
  • node_modules의 용량이 과도하게 커질 수 있다.


2. 라이브러리 중복 줄이기

  • node_modules의 용량이 과도하게 커지는 문제를 해결하기위해 npm은 라이브러리들이 시멘틱버전(semver)을 지킨다고 가정한다. major 버전이 바뀌지 않는한 더 높은 버전을 사용해도 문제가 생기지 않는다고 가정
  • npm dedupe 명령어로 중복된 모듈을 지워준다.
  • 특정 라이브러리가 다양한 버전의 라이브러리가 있다면 webpack의 resolve.alias기능을 이용하여 특정 라이브러리만 사용하도록한다.
    • lodash와 같은 라이브러리에는 다양한 라이브러리가 있다는 것이다. (lodash-es, lodash.get, lodash.isPlainObject, ...)  
    • {
        resolve: {
          alias: {
            	'lodash-es':'lodash',
              'lodash.get':'lodash/get',
              'lodash.isPlainObject':'lodash/isPlainObject'
          }
        }
  • tree shaking을 지원하지 않는 라이브러리의 경우(lodash), lodash-es를 쓰거나, babel-lodash-plugin을 이용해 사용중인 부분만 가려낼 수 있다.
  • 같은 기능을 하는  라이브러리의 경우 낮은 용량의 라이브러리를 찾아 사용한다.
    • webpack은 브라우저와 node환경을 최대한 맞추기위해 polyfill을 추가할 수 있다. 이로인해 라이브러리의 자체용량이 적어도 polyfill이 추가되어 느려질 때도 있다.
    • node-rsa 라이브러리의 경우 node.js의 지원만 생각하고 만들어진 라이브러리이기 때문에 브라우저로 넘어갈 경우 polyfill로 cryto, Buffer, big number등의 polyfill이 추가된다. (100kb)
    • bundle phobia에서 미리 용량 및 dependency를 확인한다. (export analysis)

 

라이브러리를 만들 때

tree-shaking

불필요한 코드를 정적분석을 통해 제거하는 기술. 정말 사용중인 코드만 bundle에 포함되기때문에 더 가벼운 번들을 만들 수 있다.

 

tree shaking이 어려울때

//module boo
export const a = foo();
export const b = bar();

//user
import {b} from './boo';

이때 과연 boo의 a를 bundle에서 빼도 될까? 정답은 그럴수도 있고 아닐수도 있다

// a를 제거해도 될때
function foo(){
  return 'Hello World';
}

export const a = foo();
export const b = bar();


// a를 제거해서는 안될때
let count = 0;
const foo(){
  count++;
  return count;
}

export const a = foo();
export const b = bar();

위의 코드의 경우 a를 제거해도 동작이 달라지지 않지만 밑의 코드의 경우 a를 제거하면 동작이 달라질 수 있다. 이 때를 side effect가 있다고 한다. 

tree-shaking을 하려면 side-effect가 없을때만 가능하다

이 side-effect판별능력은 bundler에 따라 다르다. webpack은 별로 안좋은편

 

 

webpack의 side-effect 판별 향상방법

webpack에게 side effect여부를 알려줘야한다. 이는 webpack에 sideEffects 필드를 설정하면된다.

이 필드가 있을때만 treeshaking을 시도한다. side effect를 발견하거나 분석이 어려운경우 tree shaking을 하지않는다.

 

프로덕션 빌드에서는 terser의 도움을 받아 deadcode를 삭제할 수 있다.

terser도 side effect의 유무를 판단하여 코드를 지운다. 이 때 terser의 판단을 돕는것이 pure annotation이다.

pure annotation이 붙어있으면 side effect가 없다고 판단한다.

const a = /*#__PURE__#*/ foo();
const b = /*#__PURE__#*/ bar();
console.log(b);


//prduction
const b =bar();
console.log(b);

side effect를 발생할때 이를 발견할 ㅅ수 있는방법은 무엇일까?

webpack의 stats (nextjs에서는 webpack-stats-plugin)를 사용한다.

 

라이브러리 영향 줄이기

라이브러리 용량을 더이상 줄이는 것이 어렵다면 무거운 라이브러리의 영향을 최소화한다.

이 때 bundle의 chunk를 나누도록한다.

 

단일 chunk일때 하나의 라이브러리가 추가되면 모든 페이지의 용량이 커지게된다.

 

dynamic import

용량이 큰 라이브러리를 필요할때만 받는 기법

import dynamic from 'next/dynamic';

const pageA = dynamic(()=> import('./PageA'));
const pageB = dynamic(()=> /*webpackPrefetch: true*/ import('./PageB'));

webpack magic comment를 사용하면 prefetch기능을 사용할 수 있다. prefetch를 이용하면 여유로운 시간에 미리 받아둔다. 

 

 

'Webpack' 카테고리의 다른 글

Package-lock.json  (0) 2021.07.27
Package.json dependencies versioning  (0) 2021.07.27
Webpack 이란?  (0) 2021.01.15
728x90

Lazy Loading 이란?

일반적으로  웹페이지는 사용자가 페이지를 열면 전체 페이지의 내용이 한번에 다운로드 되어 레더링이 이루어진다.

 

페이지의 내용이 매우 길고 사용자가 페이지 상단의 내용에만 관심이 있다면,

페이지 하단의 내용의 로딩까지 소비한 시간과 통신비용은 낭비가 된다.

 

사용자가 실제 이미지들이 실제로 화면에 보여질 필요가 있을때 비로소 해당 이미지의 로딩을 시작하는 것을 lazy lading이라고 한다.

lazy loading을 실현함으로써 페이지의 로딩시간과 통신비용을 줄일 수 있게된다.

 

Intersection Observer

사용자가 페이지를 보는지 혹은 보고있지않은지 observe 한다. 

 

다음은 사용자의 스크롤 움직임에 따라 사용자가 보고있는 section에 노란색 바탕을 채우도록 만든 코드이다. (threshold: 0.1) 보고있지 않으면 노란색 바탕은 해제된다.

See the Pen by korkt-kim (@korkt-kim) on CodePen.

callback function

  • 사용자가 특정 section을 보고있는지(intersecting)의 여부가 바뀔때마다 observe callback funtion이 실행된다
    • 현재 intersecting 여부는 entry.isIntersecting의 true/false값으로 판별한다.
  • observer : 특정 node를 observe하는 observer 자기 자신의 instance. 

options

  • options없이 기본적인 intersection observer는 viewport안에 node의 변화가 있을때마다 callback 함수를 실행시키기 때문에 무거운 감이 있다. 이를 해결하기위해 options를 사용한다.
  • root: intersecting 영역을 지정한다. observer를 동작시키기 위해서는 당연히 타겟의 조상 node element여야한다.
    default는 { root: null; } 이다. 이는 브라우저의 viewport를 intersecting 영역으로 삼겠다는 것이다.
  • threshold: section이 root element 기준 얼마 비중으로 들어와야 callback 함수를 실행할지 설정한다. 0~1의 값을 가진다.
  • rootMargin : root element안에서 intersecting 영역의 범위(px)를 설정한다. default는 0이다. "-150px" 이라면 현재 intersecting중인 페이지에서 동서남북 각각 안쪽으로 150px씩 움직인 범위안에서 intersecting여부를 찾게 된다.

lazy loading

그럼 이제 사용자가 특정 이미지를 intercept중일때만 해당 image를 로드하도록 lazy loading을 구현해보자

 

See the Pen by korkt-kim (@korkt-kim) on CodePen.

 기본적인 원리는 다음과같다.

  1. 초기에 이미지가 바로 load 못하도록 img 안 src attribute를 설정하지않는다. 여기서는 data-src로 이미지 url을 설정했다.
  2. 각 이미지 별로 intersection을 설정한다.
  3. 특정 이미지의 isIntersecting이 감지되면 해당 이미지의 data-src의 value를 src의 value로 설정해준다. 이제 해당 이미지는 load를 시작할 것이다.
  4. isIntersecting의 이미지는 이제 로드가 완료되어 더이상 observe할 필요없으므로 unobserve해준다

'Javascript' 카테고리의 다른 글

await event  (1) 2021.07.30
prototype  (0) 2021.02.14
var vs let (const)  (0) 2021.01.13
비동기 처리 - async/await  (0) 2020.12.27
비동기 처리 - Promise  (0) 2020.12.20

+ Recent posts