一张图教你快速玩转vue-cli3

徐小夕 等级 616 0 1

前言

本文系统的梳理了vue-cli3搭建项目的常见用法,目的在于让你快速掌握独立搭建vue项目的能力。你将会了解如下知识点:

  • 如何安装项目插件
  • 添加浏览器支持
  • 如何配置scss/stylus共享全局变量
  • 如何整合elementUI等第三方框架并实现按需引入
  • 配置单/多页面
  • 如何配置自定义环境变量
  • 如何在vue.config.js定制自己的webpack
  • vue项目部署

说明

本文末尾会给出一个以上提到的所有功能的一个配置文件,可供大家学习参考。

思维导图

一张图教你快速玩转vue-cli3 接下来,我们根据思维导图,一步步来解释和实现我们的目标。

1.安装项目插件

vue add @vue/cli-plugin-eslint
# 或
vue add xjFile

vue add 的设计意图是为了安装和调用 Vue CLI 插件。对于普通的 npm 包而言,我们仍然可以(根据所选的 npm 包)使用包管理器。最后可以在vue.config.js做webpack自定义配置

2.添加浏览器支持

  1. browserslist

    我们可以通过package.json 文件里的 browserslist字段或一个单独的 .browserslistrc 文件来指定项目的目标浏览器的范围。这个值会被 @babel/preset-env 和 Autoprefixer 用来确定需要转译的 JavaScript 特性和需要添加的 CSS 浏览器前缀

例如:

// .browserslistrc
> 1%
last 2 versions

想要获取更多browserslist,可移步browserslist

  1. Polyfill

默认情况下,cli会把 useBuiltIns: 'usage' 传递给 @babel/preset-env,这样它会根据源代码中出现的语言特性自动检测需要的 polyfill。这确保了最终包里 polyfill 数量的最小化。但是如果其中一个依赖需要特殊的 polyfill,默认情况下 Babel 无法将其检测出来。我们可以通过如下三种方式解决此类问题:

  • 将依赖添加到 vue.config.js 中的 transpileDependencies 选项
    // vue.config.js
    module.exports = {
      // 默认情况下 babel-loader 会忽略所有 node_modules 中的文件。如果你想要通过 Babel 显式转译一个依赖,可以在这个选项中列出来
      transpileDependencies: ['glob']
    }
  • 可以使用 @vue/babel-preset-app 的 polyfills 选项预包含所需要的 polyfill
    // babel.config.js
    module.exports = {
    presets: [
      ['@vue/app', {
        polyfills: [
          'es6.promise',
          'es6.symbol'
        ]
      }]
    ]
    }
  • 使用 useBuiltIns: 'entry' 然后在入口文件添加 import '@babel/polyfill',这种方式的问题就是会增加包的大小

3.配置scss/stylus共享全局变量

对与scss,可以使用如下方式开启:

// vue.config.js
module.exports = {
  css: {
    loaderOptions: {
      sass: {
        // 这里假设你有 `src/variables.scss` 文件
        data: `@import "~@/variables.scss";`
      }
    }
  }
}

对于stylus,本人亲测使用如上方式无效,可以通过如下方式实现:

vue add style-resources-loader

// vue.config.js
const path = require('path')
module.exports = {
  pluginOptions: {
    'style-resources-loader': {
      'patterns': [
        path.resolve(__dirname, 'src/styles/abstracts/*.styl'),
      ]
    }
  }
}

4.整合elementUI等第三方框架并实现按需引入

  1. 安装babel-plugin-component
    npm install babel-plugin-component -D
  2. 配置babel.config.js
    module.exports = {
    presets: [
     '@vue/app',
    ],
    plugins: [
     [
       "component",
       {
         "libraryName": "element-ui",
         "styleLibraryName": "theme-chalk"
       }
     ]
    ]
    }

此时即可按需引入element组件,优化项目体积了。

5.配置单/多页面

vue-cli默认单页面结构,我们可以通过配置文件来将项目配置成多页面:

// vue.config.js
const path = require('path')
module.exports = {
  // 单/多页面
    pages: {
        index: {
          // page 的入口
          entry: 'src/home/main.js',
          // 模板来源
          template: 'public/index.html',
          // 在 dist/index.html 的输出
          filename: 'index.html',
          // 当使用 title 选项时,
          // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
          title: 'Your Web For PC',
          // 在这个页面中包含的块,默认情况下会包含
          // 提取出来的通用 chunk 和 vendor chunk。
        //   chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 当使用只有入口的字符串格式时,
        // 模板会被推导为 `public/subpage.html`
        // 并且如果找不到的话,就回退到 `public/index.html`。
        // 输出文件名会被推导为 `subpage.html`。
        // subpage: 'src/subpage/main.js'
    },
}

6.如何配置自定义环境变量

你可以替换你的项目根目录中的下列文件来指定环境变量:

.env                # 在所有的环境中被载入
.env.local          # 在所有的环境中被载入,但会被 git 忽略
.env.[mode]         # 只在指定的模式中被载入
.env.[mode].local   # 只在指定的模式中被载入,但会被 git 忽略

如下:

// .env.local
APPID=123
VUE_APP_SECRET=secret

如果你想在客户端侧代码中使用环境变量,变量名因以 VUE_APP_开头,如下可获取定义的环境变量:

console.log(process.env.VUE_APP_SECRET)

7.如何在vue.config.js定制自己的webpack

我们可以使用cli支持的链式调用,或者自定义调用:

// vue-cli内部webpack配置
    chainWebpack: config => {
        // 设置快捷目录别名
        config.resolve.alias.set('utils',resolve('../utils'))

        // 修改静态资源打包方式,下例为超过10k才用文件导入的方式,否则为base64.默认为4k
        // config.module
        // .rule('images')
        //     .use('url-loader')
        //     .loader('url-loader')
        //     .tap(options => Object.assign(options, { limit: 10240 }))
    },
    // webpack自定义配置
    configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
          // 为生产环境修改配置...
        } else {
          // 为开发环境修改配置...
        }
    }

7.vue项目部署

这里我们使用shell脚本部署,当然大家也可以使用自己熟悉的方式部署:

#!/usr/bin/env sh

# 当发生错误时中止脚本
set -e

# 构建
npm run build

# cd 到构建输出的目录
cd dist

git init
git add -A
git commit -m 'deploy'

git push -f git@bitbucket.org:<USERNAME>/<USERNAME>.bitbucket.io.git master

cd -

最后,上一张相对完整的配置清单:

// vue.config.js
// 自定义vue配置
const path = require('path');
const resolve = dir => path.join(__dirname, dir);
// mock数据
const mockData = require('./mock/test.json');

module.exports = {
    // 基本路径
    publicPath: './',

    // 输出文件目录
    // outputDir: 'dist',

    // eslint-loader 是否在保存的时候检查
    // lintOnSave: true,

    // 单/多页面
    pages: {
        index: {
          // page 的入口
          entry: 'src/main.js',
          // 模板来源
          template: 'public/index.html',
          // 在 dist/index.html 的输出
          filename: 'index.html',
          // 当使用 title 选项时,
          // template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
          title: 'OpenCoder For PC',
          // 在这个页面中包含的块,默认情况下会包含
          // 提取出来的通用 chunk 和 vendor chunk。
        //   chunks: ['chunk-vendors', 'chunk-common', 'index']
        },
        // 当使用只有入口的字符串格式时,
        // 模板会被推导为 `public/subpage.html`
        // 并且如果找不到的话,就回退到 `public/index.html`。
        // 输出文件名会被推导为 `subpage.html`。
        // subpage: 'src/subpage/main.js'
    },

    // css相关配置
    css: {
        // 是否使用css分离插件 ExtractTextPlugin
        extract: true,
        // 开启 CSS source maps?
        sourceMap: false,
        // css预设器配置项
        loaderOptions: {
            // stylus: {
            //     // @/ 是 src/ 的别名
            //     // 所以这里假设你有 `src/variables.stylus` 这个文件, 不过目前测试无效
            //     data: `@import "~@/style/variables.styl";`
            //   }
        },
        // 启用 CSS modules for all css / pre-processor files.
        modules: false
   },


    pluginOptions: {
        // 共享变量
        'style-resources-loader': {
            preProcessor: 'stylus',
            patterns: [
                //这个是加上自己的路径,
                //注意:试过不能使用别名路径
                resolve('src/style/variables.styl'),
            ]
        }
    },

    devServer: {
        // 端口
        port: 3000,

        // 配置代理
        proxy: {
            '^/api': {
              target: 'http://localhost:8081',
              ws: true,
              changeOrigin: true
            },
            '^/data': {
              target: 'http://localhost:3000'
            }
        },

        // mock
        before(app){
            app.get('/api/getUser',(req,res,next)=>{
                res.json(mockData);
            })
        }
    },
    // vue-cli内部webpack配置
    chainWebpack: config => {
        // 设置快捷目录别名
        config.resolve.alias.set('utils',resolve('../utils'))

        // 修改静态资源打包方式,下例为超过10k才用文件导入的方式,否则为base64.默认为4k
        // config.module
        // .rule('images')
        //     .use('url-loader')
        //     .loader('url-loader')
        //     .tap(options => Object.assign(options, { limit: 10240 }))
    },
    // webpack配置
    configureWebpack: config => {
        if (process.env.NODE_ENV === 'production') {
          // 为生产环境修改配置...
        } else {
          // 为开发环境修改配置...
        }
    }
}

// babel.config.js
module.exports = {
  presets: [
    '@vue/app',
  ],
  plugins: [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

// .browserslistrc
> 1%
last 2 versions

// package.json
{
  "name": "pc",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "build:serve": "serve -s dist",
    "lint": "vue-cli-service lint",
    "test:unit": "vue-cli-service test:unit"
  },
  "dependencies": {
    "clipboard": "^2.0.4",
    "core-js": "^2.6.5",
    "element-ui": "^2.9.1",
    "register-service-worker": "^1.6.2",
    "serve": "^11.0.2",
    "vue": "^2.6.10",
    "vue-router": "^3.0.3",
    "vuex": "^3.0.1"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^3.8.0",
    "@vue/cli-plugin-eslint": "^3.8.0",
    "@vue/cli-plugin-pwa": "^3.8.0",
    "@vue/cli-plugin-unit-mocha": "^3.8.0",
    "@vue/cli-service": "^3.8.0",
    "@vue/test-utils": "1.0.0-beta.29",
    "babel-eslint": "^10.0.1",
    "babel-plugin-component": "^1.1.1",
    "chai": "^4.1.2",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.0.0",
    "style-resources-loader": "^1.2.1",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.2",
    "vue-cli-plugin-style-resources-loader": "^0.1.3",
    "vue-template-compiler": "^2.6.10"
  }
}

本文梳理了一个最基本的cli3项目配置流程,我们可以根据这个思维导图,去搭建自己的项目。

本文参考vue-cli官网

更多推荐

收藏
评论区

相关推荐

教你用200行代码写一个爱豆拼拼乐H5小游戏(附源码)
前言 本文将带大家一步步实现一个H5拼图小游戏,考虑到H5游戏的轻量级和代码体积,我没有使用react或vue这些框架,而采用我自己写的dom库和原生javascript来实现业务功能,具体库代码可见我的文章如何用不到200行代码写一款属于自己的js类库(https://juejin.im/post/6844903880707293198),构建工具我采
css3实战汇总(附源码)
本文是继上一篇文章用css3实现惊艳面试官的背景即背景动画(高级附源码)(https://juejin.im/post/6844903950123188237)的续篇也是本人最后一篇介绍css3技巧的文章,因为css这块知识难点不是很多,更多的在于去熟悉css3的新特性和基础理论知识。所以写这篇文章的目的一方面是对自己工作中一些css高级技巧的总结,另一
《前端实战总结》之使用解释器模式实现获取元素Xpath路径的算法
前端领域里基于javascript的设计模式和算法有很多,在很多复杂应用中也扮演着很重要的角色,接下来就介绍一下javascript设计模式中的解释器模式,并用它来实现一个获取元素Xpath路径的算法。 上期回顾 《前端实战总结》之迭代器模式的N1种应用场景(https://juejin.im/post/6844904008616771591)
使用nodeJs开发自己的图床应用
前言 本文主要复盘笔者的nodeJS,通过一个线上的实战案例来总结node生态常用的技术点和最佳实践。后面会花费大概一个月的时间输出3篇以实战为主的nodeJs项目,本文是第一篇,主要介绍如何使用nodeJs开发一个图床应用。该项目对于测试和个人服务型网站非常实用,大家可以基于此扩展出更强大的应用。本文的图床项目主要使用Koa进行开发,不熟悉的可以先研究一下
JavaScript设计模式之英雄联盟
作者:黄梵高 原文: https://juejin.cn/post/6844904165982879758 构造函数模式 简介 在Jav
golang 分析调试高阶技巧
layout: post title: “golang 调试高阶技巧” date: 2020603 1:44:09 0800 categories: golang GC 垃圾回收 golang 高阶调试 Golang tools nm compile
一文搞懂什么是HTTP与HTTPS
(https://blog.csdn.net/petterp/article/details/102779257)Http与Https的区别。 在最近的开发中,深感网络相关基础知识薄弱,于是趁周末好好总结一
20 张图彻底弄懂 HTTPS 的原理
前言 近年来各大公司对信息安全传输越来越重视,也逐步把网站升级到 HTTPS 了,那么大家知道 HTTPS 的原理是怎样的吗,到底是它是如何确保信息安全传输的?网上挺多介绍 HTTPS,但我发现总是或多或少有些点有些遗漏,没有讲全,今天试图由浅入深地把 HTTPS 讲明白,相信大家看完一定能掌握 HTTPS 的原理,本文大纲如下: HTTP 为什么不安全
Python Flask 框架使用及常见异常处理
1.jinja2.exceptions.TemplateNotFound出错 如图, 示例(https://imghelloworld.osscnbeijing.aliyuncs.com/851ef735dfc6426c04797c8f07ab877f.png) 文件夹(https://imghelloworld.osscnbei
问题 first path segment in URL cannot contain colon 的解决方案
目录问题解决 问题使用Golang开发流媒体服务器处理Post请求时,遇到了这个报错信息:2020/12/14 07:21:01 callback post failed2020/12/14 07:21:01 error::8080/api/callback: first path segment in URL cannot contain col
Golang如何解析post请求中的json字符串
目录问题解决 问题使用Golang开发服务器,最常用的使用场景之一就是处理各种http请求。那么我们如何使用Golang解析Post请求中的Json字符串呢?今天我们就来通过一个实例了解一下。 解决首先,我们需要定义好对应的消息结构,也就是前端请求服务器的API接口。定义接口的话推荐使用工具YAPI编写,支持预
PHP 微信公众号消息加解密
公众号配置根据提示设置即可:【图中信息均为无意义数据,仅供参考。注意服务器地址需可接收 GET/POST 两种请求】 AESKey 直接点一下随机生成即可,Token 可以生成一个 UUID 再把 UUID 进行 MD5 一次即可。 接收关注事件消息示例 请求参数校验这一步根据项目情况,可供参考:(Lumen 框架)php$valida
Android如何解析json字符串
前言上一篇文章介绍了服务器用Golang如何解析json字符串,今天我们来看看Android客户端是如何解析json字符串的。 正文Golang如何解析post请求中的json字符串(https://www.helloworld.net/p/O917HGeiALU2D)使用java语句如何正确解析json字符串呢?举一个例子,假如我们想从rtc_i
https://cloud.tencent.com/developer/article/write/1830331
一、目标今天的目标是这个sign和appcode 二、步骤 Jadx没法上了app加了某梆的企业版,Jadx表示无能为力了。 FRIDADEXDumpDexDump出来,木有找到有效的信息。 Wallbreaker葫芦娃的Wallbreaker可以做些带壳分析,不过这个样本,用Frida的Spawn模式可以载入,Attach模式会失败。而直接用Objecti
SpringCloud升级之路2020.0.x版-19.Eureka的服务端设计与配置
本系列代码地址:https://github.com/HashZhang/springcloudscaffold/tree/master/springcloudiifordEureka Server 配置是 Eureka Server 需要的一些配置,包括之前多次提到的定时检查实例过期的配置,自我保护相关的配置,同一 zone 内集群相关的配置和跨 zone