Skip to content

LewisLen/vue-multiple-h5

Repository files navigation

vue-multiple-cli

create mutiple page by vue-cli4.5.15

多应用,看这个工程就够了,开箱即用。

本工程是基于@vue/cli4.5.15版本搭建的多页面应用,主要是将单页面应用改造成多页面(模块)应用,使其一个脚手架可以开发多个互不影响的模块,同时又可以共用一些公共组件和方法,非常适合公司功能非常多的应用。

安装使用

git clone git@github.com:LewisLen/vue-multiple-h5.git
npm install
# 这里是以逗号或者分隔模块名称
npm run serve -- --module vip,page
npm run dev -- --module vip_page
# 模块打包
npm run build -- --module vip,page
npm run build -- --module vip_page
# 不同环境
npm run build:uat -- --module vip_page
# 全量本地启动即devServe
npm run serve
# 全量打包
npm run build

多模块应用构建

构建多模块应用的关键就是module.exports中的pages关键词,最终需要把pages变成下述格式

pages:{
  vip: {
    entry: './src/modules/vip/main.js',
    template: './public/index.html',
    filename: 'vip.html'
  },
  page: {
    entry: './src/modules/page/main.js',
    template: './public/index.html',
    filename: 'page.html'
  }
}

执行几个模块编译需要借助argv获取命令行中的参数,通过--后边可以添加参数,本工程是以下划线(_)或者逗号(,)进行分割,可以指定多个部分模块进行编译打包。

也可以使用 minimist 模块来获取 argv 字段

移动端H5适配

方案1:rem+lib-flexible

采用的的lib-flexible方案,搭配postcss-pxtorem插件可以直接在开发过程中用px做单位,插件会根据配置自动转化成rem,就可以直接在项目中写px单位,需要注意的是,本工程默认设计稿为 750px。

需要在 main.js 中引入 lib-flexible.js 或者直接在模板的 html 文件中引入该方案

npm install lib-flexible --save
npm install postcss-pxtorem --save-dev
//mian.js
import 'lib-flexible/flexible.js'
// .postcssrc.js文件
module.exports = {
  plugins: {
    "autoprefixer": {},
    "postcss-pxtorem": {
      "rootValue": 75, // 设计稿宽度的1/10
      "unitPrecision": 4, // 小数位
      "minPixelValue": 2, // 转换的最小单位
      "selectorBlackList": [], // 忽略的样式, 正则
      "propList": ["*"], // 需要做转化处理的属性,如`hight`、`margin`等,也可以正则匹配
      "exclude": /node_modules/
    }
  }
}

出现报错: Syntax Error: Error: PostCSS plugin postcss-pxtorem requires PostCSS 8. 解决方案,安装postcss-pxtorem@5.1.1版本: npm install postcss-pxtorem@5.1.1 -D

方案2: vm/vh适配方案(推荐)

安装单位转换插件

# 自动转换px单位
npm install postcss-px-to-viewport -D

新增 postcss 相关配置

// .postcssrc.js
module.exports = {
  plugins: {
    autoprefixer: {
      overrideBrowserslist: ['Android 4.1', 'iOS 7.1', 'Chrome > 31', 'ff > 31', 'ie >= 8']
    },
    'postcss-px-to-viewport': {
      viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
      unitPrecision: 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
      viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw
      selectorBlackList: ['.ignore'], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
      minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
      mediaQuery: false // 允许在媒体查询中转换`px`
    }
  }
}

脚手架采用的是方案2,方案2可能存在一些兼容性问题,特别是一些低版本手机浏览器。方案1和方案2不要混合使用。

封装axios

安装axiosqs,利用 interceptors 拦截器对 axios 请求进行封装

// 引用方式一 main.js
import request from "@/request";
Vue.prototype.$http = request;// 挂载到原型对象上
// 组件中
this.$http.get("api/productList").then((res) => {
  console.log(res);
});
// 引用方式二:每个请求按模块划分
// product.js
import request from "../request";
import QS from "qs";

export function getProductList(data) {
  return request({
    url: "api/productList",
    method: "get", // 默认是get
    data: QS.stringify(data),
  });
}

取消请求方式

// 方式一
const cancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.post('/productList',{code:'0001'},{
  cancelToken: source.token
})
source.cancel('取消请求')
// 方式二
const cancelToken = axios.CancelToken;
let cancel;
axios.get('/productList',{
  cancelToken: new cancelToken(function executor(c){
    cancel = c;
  })
})
cancel();// 取消请求

vue-router

路由懒加载

// 路由懒加载
const Task = () => import("../views/Task.vue");// ES6方式
const routes = [
  {
    path: "/task",
    name: "Task",
    component: (resolve) => require(["../views/Task.vue"], resolve),
    meta: {
      title: "任务",
      keepAlive: false, // 是否需要缓存
      auth: false, // 用户权限
    },
  }
]

路由守卫

router.beforeEach((to,from,next) => {
  // 路由拦截
  if(!to.meta.auth){
    console.log('无权限')
  }
  // 设置页面标题
  if(to.meta.title){
    document.title = to.meta.title;
  }
  next();
})

也可以通过 webpack 中的 require.context(要搜索的目录,是否要搜索子目录,匹配文件的正则表达式) 函数自动注册匹配路由。

// 自动注册路由
let tempRouters = [];
const oFiles = require.context("../views", true, /\.vue$/);
oFiles.keys().forEach((element) => {
  // element: ./Task.vue
  let componentName = element.replace(/^\.\//, "").replace(/\.vue$/, "");
  tempRouters.push({
    path: "/" + componentName.toLowerCase(),
    component: () => import("../views/" + componentName),
  });
});

externals用cdn链接的方式引入资源

externals 引入方式的作用需谨慎评估,确实能够减少编译包大小,但是需要额外在html文件上添加script标签以引入js文件,这就意味着需要额外的http请求以及更多的解析时间。

// vue.config.js
configureWebpack: config => {
  config.externals = {
    // 依赖包名称:赋值给widnow的全局变量名称
    vue: 'Vue',
    'vue-router': 'vueRouter'
  }
}

这个时候就可以手动在html模版文件中手动引入依赖包的 cdn 链接,需注意引入依赖之间以及和编译打包后的包先后顺序关系。引入的前后顺序没问题,则可以把 main.js 中 import 引入的依赖语句删除。

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>

如果有很多个 cdn 链接需要引入,则可以借助 html-webpack-plugin 插件进行插入

// vue.config.js
const externalsList = {
  css:[
    "https://cdn.jsdelivr.net/npm/reset.css"
  ],
  js:[
    "https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"
  ]
}
module.exports = {
  configureWebpack: config => {
    config.externals = {
      // 依赖包名称:赋值给widnow的全局变量名称
      vue: 'Vue',
      'vue-router': 'vueRouter'
    }
  },
  chainWebpack: config => {
    config
      .plugin('html')
      .tap(args => {
        args[0].cdn = externalsList
        return args
      })
  }
}

在 html 模版中引入,可以使用vue inspect --plugin html命令来审批配置的一部分

<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.css) { %>
  <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="preload" as="style" />
  <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
<% } %>
  <!-- 使用CDN加速的JS文件,配置在vue.config.js下 -->
<% for (var i in htmlWebpackPlugin.options.cdn && htmlWebpackPlugin.options.cdn.js) { %>
  <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
<% } %>

预编译语言

直接安装对应的loader即可

# sass
npm install -D sass-loader@10.1.1 sass

配置可以使用全局变量

css: {
  sourceMap: false,
  loaderOptions: {
    scss: {
      // 全局都可以使用的样式
      prependData: `@import "@/assets/style/variables.scss";`,
    },
  },
},

需注意 sass-loader 版本问题,用最新版有可能会出现编译报错的问题,最好是使用 sass-loader@10.1.1 版本 注意 @import "@/assets/css/variables.scss"; 后边需要加;

生产环境去掉console.log

vue-cli4 自带有去除console的插件 terser-webpack-plugin 所以直接使用即可

if (process.env.NODE_ENV === "production") {
  config.optimization.minimizer("terser").tap((options) => {
    options[0].terserOptions.compress.drop_console = true;
    return options;
  });
}

git提交规范

为了规范git提交commit信息,需要借助huskylint-stagedcommitlint工具。husky是一款Git Hook工具,可以在 git 的各个阶段(pre-commit、commit-msg、pre-push 等)触发我们的命令。而 lint-staged 的作用就是只校验 git 提交到暂存区的文件,而避免校验全部文件。

npx husky-init && npm install       # npm方式
npx husky-init && yarn              # Yarn 1方式
yarn dlx husky-init --yarn2 && yarn # Yarn 2方式

执行命令会新增husky依赖,在根目录下创建.husky目录并且会生成初始化pre-commit

"scripts":{
	"prepare":"husky install"
}

生成初始化的.husky/pre-commit文件

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx test
# 改为以下内容,则会在commit时执行以下命令,会校验所有js和vue文件
eslint --fix .src --ext .vue,.js.ts

此时需要借助lint-staged

npm install lint-staged -D

更改package.json配置信息

"lint-staged": {
	"src/**/*.{js,json,vue,ts,tsx}": "eslint --fix"
}

.husky/pre-commit文件

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx lint-staged

至此,在每次commit的时候,就会校验add文件是否符合eslint规范,如不符合则不允许提交

commitlint

# @commitlint/cli为git commit校验
# @commitlint/config-conventional规范也可以换成@commitlint/config-angular
npm install @commitlint/config-conventional @commitlint/cli -D

创建commitlint.config.js并配置信息

module.exports = {
  extends: ["@commitlint/config-conventional"]
  // 也可以换成["@commitlint/config-angular"]标准
};

.husky目录下创建commit-msg文件验证commit message提交信息

npx husky add .husky/commit-msg "npx --no-install commitlint --edit $1"

至此,在每次commit的时候,就会先校验add文件是否符合eslint规范,如不符合则不允许提交。然后再校验commit message是否符合规范,必须是以下几种类型。

  • build:编译相关的修改,例如发布版本、对项目构建或者依赖的改动
  • chore: 改变构建流程、或者增加依赖库、工具等
  • ci: 持续集成工具类改动
  • docs: 文档改动
  • feat: 新功能(业务)模块,新特性
  • fix: 修复bug
  • perf: 优化相关,比如提升性能、体验
  • refactor: 重构(即不是新增功能,也不是修改bug的代码变动)
  • revert: 回滚代码
  • style: UI走查,css样式改动
  • test: 测试用例,包括单元测试、集成测试等

如果是 vue-cli 改造,则有可能会有冲突,因为在安装之后,@vue/cli-service 也会安装 yorkie,且yorkie fork 自 husky 不兼容。如果还有问题,可以尝试删除 .git/hooks/ 下面的 pre-commit 和 commit-msg 文件再试试,按照 husky 官网再试试。

"lint-staged": {
  "src/**/*.{js,json,ts,tsx}": [
    "prettier --write",
    "eslint --fix"
  ],
  "src/**/*.{html,css,scss,sass}": [
    "stylelint --fix"
  ],
  "src/**/*.vue": [
    "prettier --write",
    "eslint --fix",
    "stylelint --fix"
  ]
}

如果有.DS_Store文件,可以执行sudo find . -name "*.DS_Store" -type f -delete命令来删除

自定义commit规范

pre-commit不生效的问题

查看.git/config文件中的hooksPath是什么,如果是要用husky,则需要配置为hooksPath=.husky,如果用默认的,则删除即可。

mac有可能没有权限执行pre-commitcommit-message脚本,需要执行chomd 777 .git/hooks/pre-commitchomd 777 .git/hooks/commit-message赋权限

stylelint(选用)

安装相关依赖,特别需要注意版本,我在这个lint浪费了不少时间,最后发现都是插件版本的问题。

vscode extension 的 stylelint 版本建议是0.87.6,依赖建议如下版本:

"stylelint": "^13.13.1",
"stylelint-config-prettier": "^9.0.3",
"stylelint-config-standard": "^22.0.0",
"stylelint-loader": "^5.0.0",
"stylelint-scss": "^4.1.0",

添加.stylelintrc.js文件,并且做规则限制

module.exports = {
  extends: [
    'stylelint-config-standard', 
    'stylelint-config-prettier', 
    
  ],
  plugins: ['stylelint-order','stylelint-scss'],
  ignoreFiles: ["./README.md","./src/assets/style/reset.css"],
  rules: {
    "selector-class-pattern": [
      // 规范class类名.box-element-modifier
      "^[a-z]([a-z0-9]){1,8}(-[a-z0-9]+)?((-|--)[a-z0-9]+)?$", 
      { 
        "resolveNestedSelectors": true,
        "message":"类名格式不对",
      }
    ],
    // ...
  }
};

参考文章