一次深入的项目复盘

737 阅读7分钟

1、项目简介

  1. 这个项目分为三个页面:首页,登录页、个人中心页。

  2. 通过vue-router对于路由来做出权限的控制。

  3. 首页无需登陆,点击个人中心按钮会检测当前是否是登录状态,若没有登录则进入到登录页,进行登录操作。登录之后进入个人中心页,首页登录按钮变为退出按钮

  4. 页面之间的状态都是通过vuex来进行管理。

项目技术栈

  • vue
  • vue-router
  • vuex
  • vue-router
  • axios
  • less
  • webpack
  • eslint

项目运行

npm install

npm run dev

启动服务

npm run dev 开发环境

npm run build 生产环境

npm ru lint 代码格式检查

2、项目结构

├── README.md                       项目介绍
├── index.html                      入口页面
├── build                           构建脚本目录
│   ├── webpack.base.conf.js            webpack基础配置,开发环境,生产环境都依赖   
│   ├── webpack.dev.conf.js             webpack开发环境配置
│   ├── webpack.prod.conf.js            webpack生产环境配置
│   ├── build.js                        生产环境构建脚本               
│   ├── dev-server.js                   开发服务器热重载脚本,主要用来实现开发阶段的页面自动刷新
│   ├── utils.js                        构建相关工具方法
├── config                          项目配置
│   ├── dev.env.js                      开发环境变量
│   ├── index.js                        项目配置文件
│   ├── prod.env.js                     生产环境变量
├── src                             源码目录    
│   ├── main.js                         入口文件
│   ├── config                          入口相关配置文件
│   ├── app.vue                         根组件
│   ├── components                      公共组件目录
│   │   └── base                          基础组件
│   │   └── layouts                       布局组件
│   │       └──header.vue                       头部组件
│   ├── styles                          样式资源
│   │   └── index.less                    样式入口
│   │   └── var.less                      变量
│   │   └── reset.less                    重置样式  
│   │   └── common.less                   公共样式  
│   ├── images                          图片资源
│   │   └── auth                          验证模块图片
│   ├── services                        接口服务
│   │   └── auth                          验证模块接口
│   ├── pages                           页面目录
│   │   └── auth                          验证模块
│   │       └── login.vue                       登录文件
│   ├── routes                          路由目录
│   │   └── auth                          验证模块
│   │       └── index.js                    验证模块入口
│   │   └── index                         所有模块汇总
│   ├── store                           应用级数据(state)
│   │   └── index.js                      所有模块数据汇总
│   │   └── type.js                       类型汇总
│   │   └── auth                          验证相关数据模块
│   │       └── index.js                    验证模块入口
│   │       └── actions.js                  actions
│   │       └── mutations.js                mutations
│   │       └── getters.js                  getters
│   │       └── state.js                    默认状态
│   
├── .eslintrc.js                        eslint规则配置
├── package.json

以上目录都是按照模块来进行划分的:

主要分为build和src两层,build层就是存放webpack配置文件。src又分为pagesimagesrouterstorecomponentsstylesservices

pages主要是用来存放业务组件

images用于存放图片

router用于控制项目路由

store用于管理页面数据

components用于存放公共的组件包括layout一些布局组件

styles用于存放一些公共的样式文件

services用于管理接口(API)

3、项目配置文件

3.1开发环境

dev-sever.js

主要分享以下几个配置重点:

DefinePlugin

new webpack.DefinePlugin({
    __DEV__: true
})

你可以理解为,通过配置了DefinePlugin,那么这里面的标识就相当于全局变量,你的业务代码可以直接使用配置的标识。

那么在你的业务代码中可以直接使用,比如有一个index.js

在index.js 你可以直接这样使用:

// index.js
if (__DEV__){
    // 任意代码
    console.log(‘这个是我通过webpack配置的全局标识’)
}

opn

//自动打开chrome浏览器
var opn=require('opn');
opn('http://localhost:8080', {app: 'chrome'});

webpack-dev-middleware && webpack-hot-middleware

var webpackConfig = require('./webpack.dev.conf')
var compiler = webpack(webpackConfig)

// webpack-dev-middleware的作用

// 1.将编译后的生成的静态文件放在内存中,所以在npm run dev后磁盘上不会生成文件

// 2.当文件改变时,会自动编译。

// 3.当在编译过程中请求某个资源时,webpack-dev-server不会让这个请求失败,而是会一直阻塞它,直到webpack编译完毕

var devMiddleware = require('webpack-dev-middleware')(compiler, {
  // 绑定中间件的公共路径,与webpack配置的路径相同
  publicPath: webpackConfig.output.publicPath,
  // 向控制台显示任何内容
  quiet: true
})

// webpack-hot-middleware的作用就是实现浏览器的无刷新更新

var hotMiddleware = require('webpack-hot-middleware')(compiler, {
  log: () => {
  }
})

3.2生产环境

webpack.prod.config.js

主要分享以下几个配置重点:

ImageminPlugin

new ImageminPlugin({
  test: 'static/img/**',
  jpegtran: {
    progressive: true,
  },
  optipng: {
    optimizationLevel: 3
  },
  maxConcurrency: Infinity,
})

CopyWebpackPlugin

new CopyWebpackPlugin([{
    from: __dirname + '/src/public'
}]);
//作用:把public 里面的内容全部拷贝到编译目录

from    定义要拷贝的源目录           from: __dirname + ‘/src/public’
to      定义要拷贝到的目标目录     from: __dirname + ‘/dist’
toType  file 或者 dir         可选,默认是文件
force   强制覆盖先前的插件           可选 默认false
context                         可选 默认base context可用specific context
flatten 只拷贝文件不管文件夹      默认是false
ignore  忽略拷贝指定的文件           可以用模糊匹配

UglifyJsPlugin

new webpack.optimize.UglifyJsPlugin({
  comments: false,//去掉注释
  compress: {
    warnings: false,//忽略警告,要不然会有一大堆的黄色字体出现……
    drop_console: true,
    pure_funcs: ['console.log']
  },
  sourceMap: false
})

CommonsChunkPlugin

new webpack.optimize.CommonsChunkPlugin({
  name: 'common',
  filename: 'static/js/[name].js?[chunkhash]',
  minChunks: Infinity,
})

minChunks

其中第一name的commons是一个entry入口,里面是一个依赖包的数组。minChunks设置为Infinity这个配置保证没其它的模块会打包进 公共chunk。因为说实话,CommonsChunkPlugin的commons分析实在是不怎么只能,还是手动控制会更好一些。 当然,你可以传入一个 function ,以添加定制的逻辑(默认是 chunk 的数量),这个函数会被 CommonsChunkPlugin 插件回调,并且调用函数时会传入 module 和 count 参数

ExtractTextPlugin

将js中引入的css分离的插件

new ExtractTextPlugin({
  filename: utils.assetsPath('css/[name].css?[contenthash]')
})

OptimizeCSSPlugin

压缩提取出的css,并解决ExtractTextPlugin分离出的js重复问题(多个文件引入同一css文件)

4、关于路由

关于的vue-router的几个要点:

首先本项目采用的是vue-router的history模式,mode为H5 history模式,这样在路由跳转的时候不会携带#

const router = new VueRouter({
  mode: 'history',
  routes,
});

关于路由有一个很重要的配置:

eg)

const Home = r => require.ensure(dependencies: String[], callback: function(require), chunkName: String);

webpack 在编译时,会静态地解析代码中的 require.ensure(),同时将模块添加到一个分开的 chunk 当中。 这个新的 chunk 会被 webpack 通过 jsonp 来按需加载

dependencies 这是一个字符串数组,通过这个参数,在所有的回调函数的代码被执行前, 我们可以将所有需要用到的模块进行声明。

callback 当所有的依赖都加载完成后,webpack会执行这个回调函数。require 对象的一个实现会作为一个参数传递给这个回调函数。

chunkName chunkName 是提供给这个特定的 require.ensure() 的 chunk 的名称。

这里边有个很重要的一点是在咱们的生产环境webpack.prod.config.js中需要加上如下配置:

output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].js?[chunkhash]'),
    chunkFilename: utils.assetsPath('js/[name].js?[chunkhash]')
  }

必须在输出的时候加上chunkFilename参数,这样打包后的文件才会跟上述路由的chunkName一致。否则打包后的js文件会按照webpack自己定义生成的类似0.js,1.js这种。

**require.ensure()**这个方法能够很成功帮助我们完成业务组件按序加载,减少app.js的体积,加速我们的项目编译及页面加载速度。

实际组件路由如下:

const Home = r => require.ensure([], () => r(require('@/pages/home/index.vue')), 'home');
const arr = [
  {
    path: '',
    name: 'home',
    component: Home,
    meta: {
      auth: false,
    },
  },
];
export default arr;

同时路由这里又做了权限的控制,调用的是上述生成的实例router.beforeEach(),然后控制meta.auth为true即可,当然这里也同样配合了vuex里的authenticated这个state数据来同时做出验证

router.beforeEach((to, from, next) => {
  const matched = router.getMatchedComponents(to); // 是否有匹配组件
  // console.log(matched);
  // 配置404页面
  if (matched.length > 0) {
    if (to.matched.some(m => m.meta.auth) && !store.state.auth.authenticated) {
      /*
       * If the user is not authenticated and visits
       * a page that requires authentication, redirect to the login page
       */
      next({
        name: 'login',
      });
    } else if (to.matched.some(m => m.meta.guest) && store.state.auth.authenticated) {
      /*
       * If the user is authenticated and visits
       * an guest page, redirect to the dashboard page
       */
      next({
        name: 'home',
      });
    } else {
      next();
    }
  } else {
    next({
      name: '404',
    });
  }
});

5、关于vuex

可以参考我的上一篇文章: 简单的vuex解析

代码请参考这里: code

6、关于eslint

在webpack.config.js配置如下:

{
    test: /\.(js|vue)$/,
    loader: 'eslint-loader',
    enforce: 'pre',
    include: [resolve('src'), resolve('test')],
    options: {
      formatter: require('eslint-friendly-formatter')
    }
  }

同样如果想定义一些自己的规则的话可以在.eslintrc.js文件中的rules修改即可

'rules': {
    'global-require': 0,
    'import/first': 0,
    'no-console': 0,
    'no-param-reassign': 0,
    'no-multi-assign': 0,

    // don't require .vue extension when importing
    'import/extensions': ['error', 'always', {
      'js': 'never',
      'vue': 'never'
    }],
    'import/no-unresolved': 0,
    'import/extensions': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
  }

7、总结

如有感兴趣的同学可以把代码copy下来跑一遍code

github:github.com/Caoyp666/vu…

此文仅供大家参考,如有不对的地方欢迎各位大佬指点!