Vue 3, Nuxt 및 TypeScript로 애플리케이션 구축

22450 단어 webdevvuetypescript
대부분의 프로젝트에서, 내가 사용하는 my own, simple setup 은 대형적이고 자바스크립트 기반 웹 응용 프로그램이다.그것의 한 가지 제한은 여러 화면 사이에서 상태를 공유하는 것이다.나의 설정은 소프트 네비게이션을 설계하지 않았기 때문에 localStorage, sessionStorageindexedDB에 의존해서 지속적인 상태를 얻어야 한다.이것은 곧 매우 번거로워질 것이다. 나는 일부 항목이 반응성과 자동 제어 메커니즘, 예를 들어 Vue와 React에 절대적으로 이익을 얻었다는 것을 인정한다.
이런 프로젝트를 세우는 것은 매우 까다로울 수 있다. 특히 선택한 틀의 전체 생태계를 이해하지 못하고 작은 프로젝트를 계속하고 싶다면.다음은 기술 스택을 선택하는 것부터 지속적인 저장소를 실현하는 것까지 연결된 응용 프로그램을 어떻게 하는가.

Vue, 반응하지 마세요.


리액트를 보기 전에 뷰에 들어갔는데 그게 이 결정에 가장 큰 역할을 했다고 생각해요.나는 Vue가 사용하기에 더욱 적합하다는 것을 발견했다.VueSingle File Components는 구성 요소를 쉽고 간결하게 포장합니다.그 밖에 Composition API와 그setup()reactive() 메커니즘도 있어 사용하기에 절대적인 즐거움이다.그러나 Vue를 사용하는 것은 (또는 이런 상황에서 React나 Angular를 사용하는 것) 커다란 단점을 가져왔다. 이것은 클라이언트가 자연스럽게 보여주는 것이다. 이것은 브라우저에 제공하는 실제 문서는 하나의 거대한 JS 파일을 가리키는 링크에 불과하다는 것을 의미한다. 이 링크가 없으면 웹 사이트에 아무런 내용도 표시되지 않는다는 것을 의미한다.사용자 체험의 측면에서 볼 때 이것은 각양각색의 단점implications이 있다.
서버에서 Vue 항목을 미리 렌더링하고 브라우저로 밀어 넣으려고 합니다.이렇게 하는 도구는 Nuxt입니다.

Nuxt 설정


Nuxt는 Vue 위에 구축된 프레임워크입니다.그 주요 기능 중 하나는 Server Side Rendering이다.Vue 구성 요소에서 완전히 채워진 문서를 만들고 서비스를 제공합니다.이 문서들은 마치 이미 완성된 사이트처럼 보이지만 아직 표현되지 않았다.모든 논리는 여전히 JS 패키지로 포장되어 있으며 브라우저에 단독으로 전송됩니다.JS가 초기화되면 일반적인 Vue 기능이 사이트에 추가됩니다.이 메커니즘은 Vue라고 불리며 Vue의 성능 문제를 해결하는 데 도움을 줄 수 있다.
프로젝트를 시작할 때 Nuxt를 사용하는 것은 구조와 구축 과정에 매우 중요하기 때문에 관건적인 결정일 수 있다.개발 프로세스의 후반부에서 Nuxt로 전환하는 데는 몇 가지 문제가 있을 수 있습니다.
설치 Nuxt에 대한 설명은 매우 상세합니다in their own documentation.저는 보통 create-nuxt-app 방식을 선택합니다. 왜냐하면 이것은 대부분의 설정 과정을 벗어날 수 있고 PWA에 좋은 작업 준비를 제공할 수 있기 때문입니다.

Nuxt와 함께 Vue 3 사용


이 문서를 작성할 때 기본적으로 Vue 2가 사용되지만 Nuxt(2.15)는 공개적으로 API를 작성하는 노드 패키지를 제공합니다.
yarn add @nuxtjs/composition-api
Vue의 새로운 기능을 사용하려면 vue에서 구성 요소를 가져오지 않고 @nuxtjs/composition-api에서 가져옵니다.
import {
    defineComponent,
    inject,
    computed,
    onMounted,
    ref,
} from "@nuxtjs/composition-api";

타자 원고


TypeScript를 사용하는 것은 선택 사항입니다.원한다면 이 단계를 완전히 뛰어넘을 수 있다.모든 항목에 타자 스크립트가 꼭 필요한 것은 아니다.
나는 그것을 사용하면 코드에 대해 자신감을 가지게 된다. 왜냐하면 데이터 구조를 실현하기 전에 그것들을 자세히 고려하도록 하기 때문이다.순수 JavaScript에서는 코드만 작성했습니다.나는 원형 디자인에 있어서 더 빠를 수도 있지만, 개발 과정에서 나의 진도를 계속 유지하는 것은 갈수록 고통스럽고 느려진다.데이터 구조를 확장해야 할 때마다 대량의 재구성이 필요하다.우선, 나는 TypeScript를 사용하여 더욱 간결한 구조를 작성하는 경향이 있다.나는 내 유형 자체가 문서이기 때문에 재구성이 더욱 쉽다는 것을 발견했다.본문에서, 나는 나의 코드 세션에서 TypeScript를 사용할 것이다. 복사하고 붙일 때 조심해야 한다.
그러나 그것도 임의의 점프를 제공하여 프로젝트의 복잡성을 증가시켰다.Vue 구성 요소를 Vanilla JS와 함께 간단하게 해독하는 것은 불가능합니다.다음은 몇 가지 주의해야 할 사항이다.

지정 언어


Vue에서 TypeScript를 실제로 사용하려면 어셈블리에 <script lang="ts">를 지정해야 합니다.

타자 도구


아이템 중의 Vuealready uses type primitives.이것들은 빈틈없이 타자 원고로 번역할 수 있다.
props: {
    id: {
        type: Number,
        required: true
    },
    name: String
},
그러나 TypeScript의 기능은 이뿐만이 아닙니다.Interfaces를 아이템 유형으로 사용하기 위해 대상 기본체를 다음과 같은 인터페이스로 변환할 수 있습니다.
interface Person {
    id: number;
    firstName: string;
    lastName: string;
    registered: boolean;
}

...

props: {
    person: {
        type: Object as () => Person
    }
}
이제 어셈블리는 해당 속성의 올바른 유형의 Person 개체만 적용됩니다.

참고 문헌을 타자하다.


Refs는 Vue의 가장 간단한 반응 기술이다.
const foo = ref<string | number>("foo");
그들의 능력도 유일무이하다work with DOM elements.그러나 DOM과 strict 유형이 만날 때마다 혼란이 생긴다.DOM 참조용ref(null) 선언.ref 값은 어셈블리가 렌더링된 경우에만 채워집니다.그 전에 이 값은null입니다.렌더링된 후에는 어셈블리 템플릿에서 설정한 HTML 요소로 채워집니다.그러나 스크립트 부분에서 HTML 요소가 어떤 유형인지 알 수 없기 때문에 TypeScript에서는 API를 사용할 수 없습니다.이 문제를 해결하기 위해서, 우리는 설정할 때 ref를 입력합니다.
<textarea ref="userInputEl"></textarea>
const userInputEl = ref<HTMLTextareaElement | null>(null);
userInputEl.value?.setSelectionRange(0, 10);

자신의 상점을 세우다


마리오 브렌델(Mario Brendel)은 우리가 Vue 3의 VueX를 더 이상 필요로 하지 않는 방법에 관한 글을 썼다.이는 결합된 API를 사용하여 여러 어셈블리에서 생성된 개체providereactive로 요약됩니다.
really nice article
그는 몇 가지 코드 세션을 공유했는데, 이 코드 세션 후에 나도 나의 상점을 모델링했다.이런 기술의 장점은 네가 VueX나 Redux 같은 거대한 것에 대처할 필요가 없다는 데 있다.반대로 당신은 완전히 자신의 필요에 따라 자신의 상점을 세웁니다.매우 간단한 실현은 다음과 같다.
import { Person, persons } from "@/data/persons.json";
import { Cat, cats } from "@/data/cats.json";
import { Dog, dogs } from "@/data/dogs.json";

interface StoreData {
    persons: Person[];
    cats: Cat[];
    dogs: Dog[];
}

export class Store {
    protected state: StoreData;

    constructor(readonly storeName: string) {
        const data = this.data();
        this.state = reactive(data);
    }

    protected data() {
        return {
            persons,
            cats,
            dogs,
        };
    }

    public getPersons(): Person[] {
        return this.state.persons;
    }

    public getCats(): Cat[] {
        return this.state.persons;
    }

    public getDogs(): Dog[] {
        return this.state.persons;
    }

    //...and all the other store logic
}

export const store = new Store("DataStore");
이것은 반응 대상에서 슬라이스로 되돌아갈 수 있는 종류를 나에게 줄 것이다.이것은 기본적으로 내가 원하는 바이다.전체 응용 프로그램에서 사용하기 위해 Composition APIprovide/inject 방법을 사용할 수 있습니다. 구성 요소 트리의 루트에 있는 기본 구성 요소는 모든 하위 구성 요소를 주입할 수 있는 저장소를 제공합니다.
// the app's base component
import { defineComponent } from "@nuxtjs/composition-api";
import { store } from "@/store/store";

export default defineComponent({
    provide: {
        store,
    },
});
// a component that needs access to the store
import { defineComponent, inject } from '@nuxtjs/composition-api';
import { Store } from '@/store/store';

export default defineComponent({
    setup() {
        const store = inject('store') as Store;
        const persons = store.getPersons();
    }
}

로컬 스토리지를 사용한 지속성


현재, 응용 프로그램이 불러오기만 하면 상점은 구축될 것이다.이것은 소프트 네비게이션에 좋지만, 하드 로드나 하드 링크를 따라가면 삭제됩니다.만약 당신의 상점에 서랍 메뉴를 열거나 닫아야 하는지, 아니면 JSON 파일에서만 정적 데이터를 불러와야 하는지 등 정보만 저장한다면 괜찮습니다.그러나 만약 당신이 작성한 표처럼 대량의 사용자 입력을 저장한다면, 단지 사용자가 페이지를 다시 불러오기 때문에 페이지를 지우는 것은 매우 번거롭다.localStorage(또는sessionStorage 또는indexedDb, 당신의 필요에 따라) 이 날을 구하세요!상점이 초기화되었을 때, 우리는 브라우저가 일부 데이터를 캐시했는지 확인하고, 이 데이터를 사용했다.그렇지 않으면 저장소가 빈 상태로 초기화됩니다.
import { FormData } from "@/data/formData.js";

interface StoreData {
    formData: FormData;
}

export class Store {
    protected state: StoreData;

    constructor(readonly storeName: string) {
        const data = this.data();
        this.state = reactive(data);
    }

    protected data() {
        const localStorage = process.browser
            ? window.localStorage
            : {
                    getItem(): string {
                        return "";
                    },
              };

        return {
            formData: localStorage.getItem("formData") || new FormData(),
        };
    }

    protected persist(key: "formData"): void {
        if (!process.browser) {
            return;
        }
        localStorage.setItem(key, String(this.state[key]));
    }

    public getFormData(): FormData[] {
        return this.state.formData;
    }

    public setFormData(payload: FormData): void {
        this.state.formData = payload;
        this.persist("formData");
    }

    //...and all the other store logic
}

export const store = new Store("FormStore");
이 예는 모든setter에서 persist() 방법을 사용하고 현재 데이터로 업데이트localStorage합니다.Nuxt에서 유사한 localStorage 브라우저 API를 사용하는 것은 매우 까다로울 수 있습니다. 왜냐하면 저희 프로그램은 서버에서 나타날 수 있기 때문입니다.이렇게 하면 서버의 노드 환경에 있을 때 저장소가 초기화됩니다.클라이언트는 여기에 저장되어 사용할 수 없습니다. (설령 사용할 수 있다 하더라도 서버는 그 내용을 알 수 없습니다.)이것이 바로 우리가 검사한 이유process.browser의 원인이다.클라이언트이고 브라우저 API에 액세스할 수 있는 경우 로 돌아갑니다true.서버에서 API와 getItem()를 저장하는 방법을 시뮬레이션하여 빈 문자열만 되돌려줍니다.다행히도 localStorage 문자열만 저장되어 있어서, 우리의 시뮬레이션을 간단하게 유지할 수 있다.

지난 일을 회고하다


이러한 절차 중의 매 단계는 프로젝트의 복잡성을 증가시켰는데 이것은 내가 매우 주목하는 문제이다.내가 보조 프로젝트를 시작할 때마다, 나는 그것이 어떻게 작동하는지 더 이상 알 수 없을 때까지 며칠 동안 그 위에서 일하고, 몇 달 동안 떠나는 경향이 있다.창고의 복잡성을 유지하는 것은 나에게 매우 중요하다.
이것이 바로 왜 나의 창고의 한 걸음 한 걸음이 모두 선택할 수 있는가 하는 것이다.작은 개념 증명과 타자 원고 하나만으로도 당신의 길을 막을 수 있습니까?그만해.당신의 응용 프로그램은 너무 작아서 상점을 지원하기에 부족합니까?그럼 하지 마.하지만 가장 중요한 것은: Vue 필요 없어요?이 글을 완전히 무시하고 더 적합한 창고를 사용하세요.

좋은 웹페이지 즐겨찾기