Vue-next (3.0) has been open source for a long time, and although it hasn’t been released yet, we’re still trying to use it in our own projects. This is a summary of my “Movie Trailer” project, which has just been rewritten with VuE3.

Project Demo Address

Project introduction

It’s been two years since MY first post on the Nuggets was about the project, and look back at the growth in the past two years…… Beat to death his heart all have!! 🙃

The overall visual/interactive effects of the project have not changed, as follows:

The front-end project

Project creation

  1. You can easily create a VUE project using the VUe-CLI tool, where you select the technology stack by checking TypeScript.

  2. After the project is initialized, install the official plug-in through vue add Vue-Next to upgrade the vUE version to VUE 3.0

  3. Modify the shims-vue.d.ts file to introduce the.vue component of the type returned by defineComponent

    declare module "*.vue" {
       import { defineComponent } from "vue";
       const Component: ReturnType<typeof defineComponent>;
       export default Component;
    }
    Copy the code

It involves points that need to change

  1. Remove filters filter characteristics, said the official reason is filters function can use function, calculate attribute to complete completely, it is not necessary to increase the learning cost, and | is conflict with an operator, but also increased the template parsing complexity. See RFC for details

  2. Modified the V-Model API and removed the Model option. $emit(‘input’) = props. $emit(‘input’) = props. Vue3.0 will use modelValue instead of value and emit(‘update:modelValue’) instead of input event. See RFC for details

<! -- Using components -->
<Comp v-mode="text" />
Copy the code
// modelValue is obtained from attrs, and emit is used to trigger the event
export default defineComponent({
  setup(props, { attrs, emit }) {
    const onChange = (e) = > {
      emit('update:modelValue', e.target.value)
    }
    return { onChange } 	
  }
})
Copy the code
  1. The className of the Transition component has been changed. Previously, the Transition effect was written in the XXX -enter, XXX -leave-to CSS className. Now, XXX -enter is changed to XXX -enter-from. See RFC for details

  2. The parameters of the plug-in install have changed. To write a plug-in, you can directly use the input Vue of the install method to mount methods or properties on vue.prototype. The input to the install method is now app.

// How the previous plug-in mounted properties
export default {
  install: (Vue, option) = >{ Vue.prototype.$axios = xxx; }}// In vue3.0 mode
export default {
  install: (app, option) = > {
    app.config.globalProperties.$axios = xxxx
  }
}
Provide and inject are also available in the Composition API
export const symbolKey = Symbol('_axios_');
The setup function uses the Composition API
export function useAxios() {
  return inject(symbolKey)
}
// Perform plug-in insall method injection
export default {
  install: (app, option) = > {
    app.provide(symbolKey, xxx)
  }
}
Copy the code

There are a lot of changes in vue3.0, but because the project is not very complex, it is not very comprehensive. You can read the RFCS to see some of the changes discussed.

Application of the Composition API

All components of the project were developed using the Composition API, which enabled us to better encapsulate common logic.

The encapsulation of the request function

Prior to this, the loading of asynchronous requests for the project needs additional definition and maintenance. With the Composition API we can encapsulate a hook function similar to the React SWR fetch library.

// something like this
export function useRequest(url, params, config) {
  // Unified maintenance of variables, and finally return out
  const state = reactive({
    loading: false.error: false.data: config.initialData
  })
  
  const fetchFunc = () = > {
    state.loading = true;
  	// Do the common logic of the request
    axios().then(response= > {
       const result = response.data;
       state.data = result.data;
       state.loading = false;
    }).catch(err= > {
       state.error = true;
    })
  }
  
  onMounted(() = > {
    if(config.immediate) { fetchFunc(); }});// toRefs can break state into multiple refs, so that the caller can use deconstructing to get the variable
  return { ...toRefs(state), fetch: fetchFunc };
}
Copy the code

Encapsulation of events

For the Touch event, not only do we need to bind the event and unbind the time, but we also need to share a side effect variable between the different callbacks, which we can split into a Composable function

// something like this
export function useTouch(domRef, ref) {
  // Whether to touch the in-progress flag bit
  let initiated = false;
  // Listen for domRef changes
  watch(domRef, (el, prev, onCleanup) = > {
    const touchStart = (e: TouchEvent) = > {
      e.preventDefault();
      initiated = true;
      callbacks.touchStart(e);
    };
   	const touchMove = (e: TouchEvent) = > {
      e.preventDefault();
      if(! initiated)return;
      callbacks.touchMove(e);
    };
    const touchEnd = (e: TouchEvent) = > {
      initiated = false;
      callbacks.touchEnd(e);
    };
    
    el.addEventListener("touchstart", touchStart);
    el.addEventListener("touchmove", touchMove);
    el.addEventListener("touchend", touchEnd);
	// Cancel the binding
    onCleanup(() = > {
      el.removeEventListener("touchstart", touchStart);
      el.removeEventListener("touchmove", touchMove);
      el.removeEventListener("touchend", touchEnd); }); })}Copy the code

To optimize the

Added Travis to deliver automated build publications, sending static resources to remote servers via the sshPass implementation.

language: node_js
node_js:
  - 12
branchs:
  - master
addons:
  apt:
    packages:
    - sshpass
install:
  "npm install"
script:
  - "npm run build"
after_success:
  - ./script/deploy.sh
Copy the code

ServerPass and serverIP are both environment variables configured on Travis.

#! /usr/bin/env sh

Make sure the script throws the errors it encounters
set -e

# Package static resources
npm run build

# Send dist file to remote
sshpass -p ${serverPass} scp -o stricthostkeychecking=no -r dist/ root@${serverIP}:/home/web/movie-trailer
Copy the code

The back-end project

The back end was upgraded from koA framework to Egg framework. When developing applications with KOA, developers needed to download or develop various middleware to achieve functional enhancements, and Egg chose KOA as its basic framework to help developers make some enhancements.

In addition to providing the Controller and Service layers for business processing, the Egg also provides the extend function for extending itself (multiple extension points). For example, we can extend the Context to mount the generic function that returns the result.

// app/extends/context.js
module.exports = {
  sendSuccess: function(result) {
    this.body = {
      code: 200.errMsg: ' '.data: result
    }
  },
  sendError: function(errorMsg) {
    this.body = {
      code: 300.errMsg: errorMsg,
    }
  }
};
// app/controller/keyword.js
class KeyWordController extends Controller {
  async index() {
    const { ctx, service } = this;

    const keywordList = await service.keyword.index();
	// Return 200 success
    ctx.sendSuccess(keywordList)
  }
}
Copy the code

The Egg framework makes it easy for developers to set up scheduled tasks. With the Egg, we only need to create a file export class in the app/schedule directory and export it based on Subscription.

class CrawlingDouban extends Subscription {
  // Static method to define the execution time
  static get schedule() {
    return {
      cron: '0 8 * * *'.// At 8 o 'clock every day
      type: 'worker'}; }async subscribe() {
  	// Crawl logic}}Copy the code

conclusion

During refactoring, there are still some problems, mostly due to unread documentation, so it’s important to go through the documentation. Hope this article is helpful to everyone, feel the project is ok, don’t be stingy with start! .

The project address

reference

  • vue-composition-api

  • vue-router-next

  • vue-composition-toolkit