vue-cli 3.x搭建项目以及其中vue.config.js文件的配置
1、项目的基本创建(官方文档:https://cli.vuejs.org/zh/guide/)
- 安装@vue/cli
1、卸载vue-cli 2.x版本 npm uninstall vue-cli -g 2、安装@vue/cli 3.x版本 npm install -g @vue/cli
3、查看版本号
vue --version 或者 vue -V - 特点
- 移除了配置文件目录,config 和 build 文件夹;
- 移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中;
- 在 src 文件夹中新增了 views 文件夹,用于分类 视图组件 和 公共组件;
- 部分命令行发生变化:创建项目、运行项目
- 创建项目的步骤
- 创建项目文件
vue create 项目名称 在2.x版本中 为 vue init webpack
- 选择配置(第一个第二个为你之前安装的项目配置,第三个为默认配置(什么配置都没有,例如路由),第四个为自行配置,建议选第四个)
- 创建项目文件
-
- 自行选择安装配置(如果不熟悉模块代表了什么,可以先按照下图选择)
这个自行选择配置,按上下键切换目标选项,按空格键勾选和取消,按a全选,按i反选,选好后回车确定 1、Babel,转译成浏览器可识别的语言,可以让你的项目支持最新的语法,如es6\es7等 2、TypeScript,新增的选项卡 3、PWA,模拟原生app,渐进式网络应用程序(渐进式增强WEB应用) 4、路由 5、vuex管理模式 6、css预处理语言 7、代码规范 8、组件单元测试 9、端对端测试,模拟用户真实场景
- 自行选择安装配置(如果不熟悉模块代表了什么,可以先按照下图选择)
-
- 选择路由模式(一般选择hash yes代表history)
-
- 选择css预处理语言
-
- 选择代码规范配置
-
- 是否保存当前配置信息(第一个为保存,由于我是演示一下,所以就不保存了)
-
- 选择babel,postcss,eslint配置文件存放位置(建议第一个)
- 最后状态为:
-
- 最后是否将配置项保存为预设,配置完成,生成项目;
- 运行项目:
npm run serve vue 2.x中的启动方式为npm run dev
2、vue.config.js文件
- 前言
在使用vue-cli3创建项目后,因为webpack的配置均被隐藏了,当你需要覆盖原有的配置时,则需要在项目的根目录下,新建vue.config.js文件,来配置新的配置。
- 基本配置:这里贴一个我常用的
'use strict' const glob = require('glob') const userConfig = require('./src/config/user.config.js') const os = require('os') const webpack = require('webpack') const pages = {} //获取本机ip const network = os.networkInterfaces() let localhost = '' Object.keys(network).forEach(outerKey => { if (outerKey == 'WLAN' || outerKey == '以太网') { Object.keys(network[outerKey]).forEach(innerKey => { if (network[outerKey][innerKey].family == 'IPv4') { localhost = network[outerKey][innerKey].address } }) } }) glob.sync('./src/pages/**/app.js').forEach(path => { const chunk = path.split('./src/pages/')[1].split('/app.js')[0] pages[chunk] = { entry: path, template: 'public/index.html', filename: `${chunk}.html`, chunks: ['chunk-vendors', 'chunk-common', chunk] } }) module.exports = { baseUrl: process.env.NODE_ENV === 'production' ? dossierConfig.PRO_PUBLIC_PATH : dossierConfig.DEV_PUBLIC_PATH, outputDir: `dist${dossierConfig.PRO_PUBLIC_PATH}`, pages, runtimeCompiler: true, productionSourceMap: false, lintOnSave: false, devServer: { host: localhost, port: 8022, open: true, proxy: { '/user': { target: 'http://10.0.0.0:8899', ws: true, changeOrigin: true, pathRewrite: { "^/user": "/", } } } }, css: { loaderOptions: { sass: { data: '@import "@/styles/index.scss";' } } }, configureWebpack: { plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery", "window.jQuery": "jquery", _: "lodash" }) ] }, chainWebpack: config => { config.module .rule('iview') .test(/iview.src.*?js$/) .use('babel') .loader('babel-loader') .end() Object.keys(pages).forEach(page => { config.plugins.delete(`preload-${page}`) config.plugins.delete(`prefetch-${page}`) }) } }
3、环境变量(NODE_ENV)
- 开发模式 development、测试模式 test、生产模式 production
- 注解:我们通常用环境变量NODE_ENV来进行区分;
4、@vue/cli中最大的特点:可视化
- windows + R 打开命令行,输入命令vue ui
- 在本地浏览器将自动打开一个服务,出现一个非常舒服的界面
- 创建项目
- 填写项目名称 -----> 选择项目的目录 -----> 选择包管理器 -----> 点击 ‘下一步’
-
- 下面的操作跟cmd命令行大致一样,不在具体阐述
- 管理项目
- 导入项目
5、vue3.0的性能提升主要是通过哪几个方面体现的???
- 编译阶段的优化
- Diff算法优化(静态标记并提升)以及事件监听缓存
1 vue.js 3.x中标记和提升所有的静态节点,diff的时候只需要对比动态节点内容; 2 Fragments(升级vetur插件): template中不需要唯一根节点,可以直接放文本或者同级标签 3 静态提升(hoistStatic),当使用 hoistStatic 时,所有静态的节点都被提升到 render 方法之外.只会在应用启动的时候被创建一次,之后使用只需要应用提取的静态节点,
随着每次的渲染被不停的复用,同时patch flag的值为-1,表示永远不会用于DIff;4 patch flag, 在动态标签末尾加上相应的标记,只能带 patchFlag 的节点才被认为是动态的元素,会被追踪属性的修改,能快速的找到动态节点,而不用逐个逐层遍历,提高了
虚拟dom diff的性能。 5 缓存事件处理函数cacheHandler,避免每次触发都要重新生成全新的function去更新之前的函数 6 tree shaking 通过摇树优化核心库体积,减少不必要的代码量 - 源码体积的优化:移除了一些不常用的API(inline-template、filter等),再重要的是
Tree-shaking
- 什么是Tree-shaking???
- 其实用大白话来说,就是通过工具“摇”我们的JS文件,然后将其中的无用代码“摇出去”,其实是一个性能优化的范畴;
- 工作流程:webapck有一个入口文件(相当于树干),这个文件所依赖的所有模块(相当于树枝),但是在实际的情况中,有些模块虽然引入了,但是只用到了其中的一些功能,有些功能未使用,因此通过Tree-shaking这个工具,可以将无用的代码“摇掉”,从而起到删除无用代码的目的。
- 什么是Tree-shaking???
-
- Tree-shaking的工作原理
- 传统的DCE(dead code elimination),dead code 一般有以下特性:
-
代码不会被执行,不可到达;
代码执行的结果不会被用到;
代码只会影响死变量(只写不读);
-
- Tree-shaking消除原理依赖的是ES6的模块特性,而ES6模块的特点:
- 只能作为模块顶层的语句出现
- import 的模块名只能是字符串常量
- import binding 是 immutable的
- 三大工具的Tree-shaking
- rollup
- 无用函数消除:消除无用代码,最终结果比较简洁 无用类消除:无法消除
- webpack
- 无用函数消除:消除无用代码,结果比较复杂 无用类消除:无法消除
- Closure Complier
- 无用函数与无用类都可以消除,但是应用了google的侵入式约束规范,会在代码里面添加一些代码,并且是由JAVA编写的,所以使用复杂,与我们日常的基于node的开发流很难兼容
- rollup
- 缺点:目前处于发展阶段,还有一些目前无法解决的问题~~~
- 传统的DCE(dead code elimination),dead code 一般有以下特性:
- Tree-shaking的工作原理
- 响应式系统的原理:代码解析
function trigger() { console.log("触发视图更新") } /** * @description isObject 判断是否是对象 * @param {*} target * @returns {Boolean} true - 是对象 false - 不是对象 * @author wxh */ function isObject(target) { return typeof target === "object" && target !== null } /** * @description 设置一个hash表 存放代理后的对象 */ const toProxy = new WeakMap() /** * @description 设置一个hash表 存放代理前的对象 */ const toRaw = new WeakMap() /** * @description reactive * @param {Object} target * @returns {Object} 一个响应式对象 * @author wxh */ function reactive(target) { if (!isObject(target)) { return target } if(toProxy.get(target)){ return toProxy.get(target) } if(toRaw.has(target)){ return targe } let handlers = { set(target, key, value, receiver) { /** * 改变属性触发方法,而Proxy可以监听到数组的索引和length属性,所以设置是私有属性才会触发视图更新 */ if (target.hasOwnProperty(key)) { trigger(); } /** * */ return Reflect.set(target, key, value, receiver) }, get(target, key, receiver) { // 获取属性触发方法 let res = Reflect.get(target, key, receiver); if (isObject(target[key])) { // 使用递归生成响应式对象 return reactive(res) } else { return res } }, deleteProperty(key) { // 删除属性触发方法 return Reflect.deleteProperty(key) } } /** * Proxy这个构造函数,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截(也就是说目标对象一旦发生变化,就会触发拦截器) * 因此提供了一种机制,可以对外界的访问进行过滤和改写 * target 表示目标对象 * handlers 是一个对象,用来定制拦截行为 */ let observers = new Proxy(target, handlers); toProxy.set(target,observers) toRaw.set(observers,target) return observers } let obj = { name: 'andy', age: '18', certificate: ["cet-4", "cet-6"] } let proxyObj = reactive(obj) proxyObj = reactive(obj) proxyObj = reactive(obj) proxyObj.certificate.push('ntce') console.log(obj)
- 响应式系统提升
vue2使用object.definepropery()方法来劫持整个对象,然后递归遍历data中的每个属性,为每个属性添加getter和setter使之变为响应式对象。如果属性值为对象,还会递归
调用object.definepropery()使之变为响应式对象。 vue3使用proxy对象重写响应式系统。proxy的性能本来比defineproperty好,因为proxy可以对整个对象进行监听,拦截属性的访问、赋值、删除等操作,不需要初始化的时候遍
历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性。
优势:- 可以监听动态新增的属性;
- 可以监听删除的属性 ;
- 可以监听数组的索引和 length 属性;
proxy相比于defineProperty有哪些优点???
proxy的性能本来比defineproperty好,proxy可以拦截属性的访问、赋值、删除等操作,不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性。
- 可以* 监听数组变化
- 可以劫持整个对象
- 操作时不是对原对象操作,是 new Proxy 返回的一个新对象
- 可以劫持的操作有 13 种
6、遇到的问题
暂无
北栀女孩儿