Vue3之JSX开发模式搭建或(.vue) script setup-技术栈( Vite2+Vue3+TypeScript+Pinia)

2,002 阅读2分钟

Vue.js 框架作者尤雨溪宣布:Vue3 将在 2022 年 2 月 7 成为新的默认版本, 还有就是状态管理工具库 Pinia 也纳入官方维护, Vue3也即将成为默认版本,那作为技术员,不搞起来,有点对不起头发呀.

641.png

对于使用 React 的重度用户,对于 hooks 和 JSX 都爱不释手吧. vue3 现在也是开发起来非常丝滑的哦. 加上 Volar 工具的加持,你值得拥有.

源码传送门

script setup

script setup是在单文件组件 (SFC) 中使用组合式 API的编译时语法糖。

<template>
  <button @click="inc">点我</button>
  <p>{{ count }}</p>
</template>

<script setup lang="ts">
const props = defineProps({
  // 注意这是只读的
  count: {
    type: Number,
    required: true,
  },
});
const emit = defineEmits(["inc"]);

const inc = () => {
  console.log("child", props.count);
  emit("inc", Math.random());
};

const someFn = () => {
  console.log("defineExpose");
};
// 暴露给组件实例调用的属性方法
defineExpose({
  someFn,
  a: 3,
});
</script>

<style></style>

jsx 使用

import { defineComponent, ref, onMounted } from "vue";

import { NButton } from "naive-ui";

import Counter from "@/components/Counter.vue";

export default defineComponent({
  name: "App",
  setup() {
    const count = ref<number>(0);

    const refCounter = ref<any>(null);
    
    const handleInc = (v: number) => {
      console.log("parent method", v);
      count.value = v;
      // 通过组件实例组件获取组件自己内部通过 defineExpose 暴露的信息
      console.log(refCounter.value.a);
      refCounter.value.someFn();
    };
    
    onMounted(() => {
      console.log("mounted");
    });

    return () => (
      <>
        {/* 注意子组件传递出来的,名字格式  onXxx 的形式*/}
        <Counter ref={refCounter} count={count.value} onInc={handleInc} />
      </>
    );
  },
});

package.json 文件信息

{
  "name": "Vite2-Vue3-TypeScript-Pinia-JSX",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "dev": "vite",
    "serve": "yarn build && yarn dev preview",
    "build": "vite build",
    "build:dev": "vue-tsc --noEmit && yarn build --mode development",
    "build:pro": "vue-tsc --noEmit && yarn build --mode production",
    "lint": "eslint src --ext .ts,.tsx,.vue,.js,.jsx",
    "lint:fix": "eslint src --fix --cache --ext .ts,.tsx,.vue,.js,.jsx",
    "prettier": "prettier --write src/**/*.{js,css,md,ts,tsx,vue}",
    "prepare": "husky install"
  },
  "devDependencies": {
    "@commitlint/cli": "^16.2.1",
    "@commitlint/config-conventional": "^16.2.1",
    "@types/node": "^17.0.21",
    "@types/nprogress": "^0.2.0",
    "@typescript-eslint/eslint-plugin": "^5.12.1",
    "@typescript-eslint/parser": "^5.12.1",
    "@vitejs/plugin-vue": "^2.2.2",
    "@vitejs/plugin-vue-jsx": "^1.3.7",
    "@vue/compiler-sfc": "^3.2.31",
    "@vue/eslint-config-prettier": "^7.0.0",
    "@vue/eslint-config-typescript": "^10.0.0",
    "eslint": "^8.10.0",
    "eslint-config-prettier": "^8.4.0",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-vue": "^8.5.0",
    "husky": "^7.0.4",
    "prettier": "^2.5.1",
    "sass": "^1.49.9",
    "typescript": "^4.5.5",
    "vite": "^2.8.4",
    "vite-plugin-compression": "^0.5.1",
    "vue-tsc": "^0.32.0"
  },
  "dependencies": {
    "axios": "^0.26.0",
    "naive-ui": "^2.25.5",
    "nprogress": "^0.2.0",
    "pinia": "^2.0.11",
    "vue": "^3.2.31",
    "vue-router": "^4.0.12"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "src/**/*.{js,css,md,ts,tsx}": [
      "yarn prettier",
      "yarn lint:fix",
      "git add"
    ]
  },
  "license": "MIT"
}

vite 配置

import path from "path";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
import viteCompression from "vite-plugin-compression";

export default defineConfig({
  base: "./", // 开发或生产环境服务的公共基础路径 ,https://vitejs.bootcss.com/guide/build.html#public-base-path
  build: {
    outDir: "dist", // 打包后的文件名称,
    terserOptions: {
      // 生产环境下移除 debugger console
      compress: {
        drop_console: false,
        drop_debugger: true,
      },
    },
    rollupOptions: {
      output: {
        // manualChunks(id) {
        //     if (id.includes('node_modules')) {
        //         return id.toString().split('node_modules/')[1].split('/')[0].toString();
        //     }
        // }
        manualChunks: {
          odash: ["lodash"],
        },
      },
    },
  },
  plugins: [
    vue(),
    // 支持 jsx 写法
    vueJsx({
      transformOn: true,
      mergeProps: true,
    }),
    // gzip压缩 生产环境生成 .gz 文件
    viteCompression({
      verbose: true,
      disable: false,
      threshold: 10240,
      algorithm: "gzip",
      ext: ".gz",
    }),
  ],

  resolve: {
    extensions: [".ts", ".tsx", ".js", ".jsx", ".json"], // vite 后缀查找
    alias: {
      "@": path.resolve(__dirname, "src"), // 别名路径
    },
  },

  css: {
    preprocessorOptions: {
      scss: {
        additionalData: '@import "@/assets/style/global.scss";', // 配置全局 scss
      },
    },
  },

  optimizeDeps: {
    include: [], // 第三方库
  },

  //启动服务配置
  server: {
    open: true, // 是否自动打开浏览器
    https: false, // 是否开启https
    port: 3000, // 端口号
    host: true, // 指定服务器应该监听哪个 IP 地址。 如果将此设置为 0.0.0.0 或者 true 将监听所有地址,包括局域网和公网地址。
    hmr: {
      // 热替换
      overlay: true, // 是否开启错误的阴影层
    },
    proxy: {
      "/api": {
        target: "http://xxx.xx.x", // 后台接口,
        changeOrigin: true,
        secure: false, // 如果是 https 接口需要配置这个参数
        // ws:false, // websocket
        rewrite: (path) => path.replace(/^\/api/, ""), // 路径重写
      },
    },
  },
});

源码传送门