使用vue-cli搭建一个vue2的项目框架

1,367 阅读5分钟

背景

前段时间使用webpack搭建了一个项目,感觉收获颇多。附上链接,大家有兴趣可以看一下( 使用webpack配置一个项目)。但是现在开发项目,直接使用webpack搭建项目,配置过于复杂,不能开箱即用,大家也早就抛弃了这种方式,而是使用vue-cli,create-react-app等脚手架针对技术栈直接搭建项目,方便快捷。今天尝试手撕一遍vue-cli搭建一个pc的项目。

预设技术栈 vue+vuex+vue-router+less+axios+element-ui, eslint+prettier+husky+lint-staged

  • vue (项目框架)
  • vuex (状态机)
  • vue-router (路由)
  • less (css预处理器)
  • axios (进行接口请求)
  • element-ui (组件库,便捷开发)
  • eslint prettier (代码风格统一)
  • husky lint-staged(在git提交的时候添加eslint检测钩子,保证所有的同学提交的代码风格都统一)

1.全局安装vue-cli

vue-cli指南

// 终端命令行
yarn global add @vue/cli
// 查看vue-cli版本
vue --version

2.使用vue-cli初始化一个项目

vue-cli配置参考

1.初始化项目

// 终端
vue create vue2-js-template  // vue2-js-template是我的项目名,大家可以随便取名字

200d751b-c5c2-4c4a-bc0f-55090ce7aa2a.png

yarn serve 打开项目,好啦,完成了。(🐶头保命,哈哈,不过第一步确实完成了)

3.修改为多页面配置项目

1.修改目录结构

image.png

2.创建vue.config.js

//  yarn add image-webpack-loader webpack-bundle-analyzer -D  终端运行
const path = require("path");

const BundleAnalyzerPlugin =
  require("webpack-bundle-analyzer").BundleAnalyzerPlugin; // 打包分析

const { NODE_ENV } = process.env;
const isProduction = NODE_ENV === "production";
const isDevelopment = NODE_ENV === "development";

// 多页面打包配置
const getPages = () => {
  return {
    index: {
      entry: "src/pages/index/main.js", // page 的入口
      template: "public/index.html", // 模板来源
      filename: "index.html", // 在 dist/index.html 的输出
      title: "首页", // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
      chunks: ["chunk-vendors", "chunk-common", "index"],
    },
    list: {
      entry: "src/pages/list/main.js", // page 的入口
      template: "public/index.html", // 模板来源
      filename: "list.html",
      title: "列表页面",
      chunks: ["chunk-vendors", "chunk-common", "list"],
    },
  };
};

const getDevServe = () => {
  const devServer = {
    overlay: {
      warnings: false, // 让浏览器 overlay 同时显示警告和错误
      errors: true,
    },
    https: false, // https:{type:Boolean}
    open: true, //配置自动启动浏览器
    hotOnly: true, // 热更新
    proxy: {
      // 配置多个跨域
      "/api": {
        target: "http://xxx.xxx",
        changeOrigin: true,
        // ws: true,//websocket支持
        secure: false,
        pathRewrite: {
          "^/api": "/",
        },
      },
    },
  };
  if (isDevelopment) {
    // 配置开发环境  访问路径跳转相关的html   http://localhost:8088/list#/ =>  http://localhost:8088/list.html#/
    const pages = getPages();
    Object.keys(pages).forEach((page) => {
      Reflect.set(devServer.proxy, `/${page}`, {
        target: "./",
        bypass: (req) => {
          const { path } = req;
          return path.indexOf("html") !== -1 ? path : `${path}.html`;
        },
      });
    });
  }
  return devServer;
};

const getChainWebpack = (config) => {
  config.module
    .rule("images")
    .use("image-webpack-loader")
    .loader("image-webpack-loader")
    .options({
      bypassOnDebug: true,
    })
    .end();
  if (isProduction) {
    config.plugin("webpack-report").use(BundleAnalyzerPlugin, [
      {
        analyzerMode: "static",
      },
    ]); // 打包环境做打包后文件大小分析展示
  }
};

const setOptimization = (config) => {
  // 提取公共chunk和node_modules的公共文件
  config.optimization = {
    splitChunks: {
      cacheGroups: {
        common: {
          //抽取所有入口页面都需要的公共chunk
          name: "chunk-common",
          chunks: "initial",
          minChunks: 2,
          priority: 1,
          enforce: true,
          minSize: 0,
          reuseExistingChunk: true,
        },
        vendor: {
          test: /[\\/]node_modules[\\/]/,
          name: "chunk-vendors",
          chunks: "all",
        }, // node_modules的打包文件
      },
    },
  };
};

module.exports = {
  pages: getPages(), // 入口文件配置
  publicPath: "./", // 打包资源引入,使用相对路径的引入,打出来的包可以被部署在任意路径
  lintOnSave: !isProduction, // 生产环境禁用eslint-loader,可以加快生产构建
  parallel: true, // 是否为 Babel 或 TypeScript 使用 thread-loader,多线程打包
  css: {
    requireModuleExtension: true, 
  },
  pluginOptions: {
    "style-resources-loader": {
      preProcessor: "less",
      patterns: [path.resolve(__dirname, "./src/style/variable.less")], // 设置less变量覆盖
    },
  }, //这是一个不进行任何 schema 验证的对象,因此它可以用来传递任何第三方插件选项
  devServer: getDevServe(), // 开发环境dev-serve配置
  chainWebpack: (config) => getChainWebpack(config), // 通过 webpack-merge 合并到最终的配置中
  configureWebpack: (config) => {
    setOptimization(config);
  }, // 是一个函数,会接收一个基于 webpack-chain 的 ChainableConfig 实例。允许对内部的 webpack 配置进行更细粒度的修改。 一般可以用来做config的一些配置的更改
};

4.添加axios相关配置

axios配置

1.安装axios

yarn add axios  // axios库
yarn add qs  // 做请求参数序列化使用

2.新建 src/config/axios.config.js

import axios from "axios";
import qs from "qs";

const instance = axios.create({
  baseURL: "", // `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
  timeout: 20000, // 如果请求时间超过 `timeout` 的值,则请求会被中断
  headers: {
    ["Cache-Control"]: "no-cache",
    ["Content-Type"]: "application/json",
    ["x-requested-with"]: "XMLHttpRequest",
  }, // 自定义请求头
  paramsSerializer: function (params) {
    return qs.stringify(params, { arrayFormat: "indices" });
  }, // `paramsSerializer`是可选方法,主要用于序列化`params`
});

// 添加请求拦截器
instance.request.use(
  (config) => {
    // 在发送请求之前
    // 携带用户的token信息
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
instance.response.use(
  (response) => {
    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  },
  (error) => {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

export default instance;

5.添加elementUI组件库

elementUI官网

1.安装elementUI

yarn add element-ui

2.在使用elementUI组件库的页面的main.js引入elementUI (src/pages/index/main.js)

 // main.js 
import ElementUI from "element-ui";
import "element-ui/lib/theme-chalk/index.css";

Vue.use(ElementUI);

6.处理eslint和prettier的规则(做一些自定义规则)

1.从package.json里面去除 eslintConfig,新建.eslintrc.js

module.exports = {
    root: true,
    env: {
        node: true,
        browser: true,
        es6: true,
    },
    extends: ['plugin:vue/essential', 'eslint:recommended', '@vue/prettier'],
    parserOptions: {
        parser: 'babel-eslint',
    },
    rules: {
        'no-multiple-empty-lines': 0, // 禁用不允许多行空格
    },
};

2.新建.prettierrc.js

module.exports = {
    printWidth: 200, //一行的字符数,如果超过会进行换行,默认为80
    tabWidth: 4, //一个tab代表几个空格数,默认为80
    useTabs: false, //是否使用tab进行缩进,默认为false,表示用空格进行缩减
    semi: true, //行位是否使用分号,默认为true
    singleQuote: true, //字符串是否使用单引号,默认为false,使用双引号
    bracketSpacing: true, // 对象左右两侧需要空格
    jsxBracketSameLine: false, // html 关闭标签换行
};

3.vscode的setting.json设置保存时候自动格式化

//setting.json
{
    "editor.formatOnPaste": true,
    "eslint.enable": true, //是否开启vscode的eslint
    "eslint.alwaysShowStatus": true, //是否在保存的时候自动fix eslint
    "eslint.options": {
        //指定vscode的eslint所处理的文件的后缀
        "extensions": [".js", ".vue", ".ts", ".tsx"]
    },
    "eslint.validate": [
        //确定校验准则
        "javascript"
    ],
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
    }
}

4.新建.eslintignore文件

**/node_modules/*
**/dist/*

5.运行eslint检测,格式化

yarn run lint
//注意:运行完成后,会有很多报错,显示出eslint和prettier冲突的感觉,需要关闭,重新启动一下vscode,让vscode重新读取.eslintrc.js的文件,就可以了

7. husky + lint-staged

1.配置

终端运行
1.//安装husky,lint-staged
yarn add husky lint-staged -D
2.// 配置husky
npx husky install
3.// 添加 pre-commit 的 git hook 脚本 
npx husky add .husky/pre-commit "npx lint-staged"

4.// package.json 添加 lint-staged的命令
 "lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": [
      "npm run lint"
    ]
  },

2.检测

(1)关闭setting.json中的自动保存

(2)在代码中改动出一个不符合规范的代码片段,使用git提交,测试结果 修复了代码问题

代码仓库

github.com/maqianbo-we…

小结

还有很多项目中使用的东西没有配置进去,但是一个简单的小框架确实是做好了,下期再见。