vue-cli3 AND webpack4
Vue-cli3
基础生成
-
vue-cli3 安装全局
运行
cnpm install -g @vue-cli
-
vue -h,--help
vue -v,--version
查看当前版本create 创建新项目
add 往项目里面添加新的插件
invoke 已经创建好的项目去调用该插件
inspect 检查 webpack 的配置
serve 开发环境 npm server
build 生产环境 需要打包到 build
ui 打开一个 vue-cli 的ui界面进行配置 以及项目调整~
init 生成一个项目
- 如果还是不了解那个命令 可以进行
vue create --help
这样可以进行详细说明
- 如果还是不了解那个命令 可以进行
- 运行
vue create 项目名称
- default 默认安装 Manually 多个自己选择
- Manually ( 空格 选中 回车之后可以进行下一步操作 )
- in dedicated config files 这个是安装到各自的文件 In package.json 这个是安装到json里面
- 先选择 package.json
- save this as a preset for future projects? 这个是一个预处理的东西
- 最后 enter 之后就表示创建完毕了
- 然后 cd 项目 npm run serve 就可以运行了
- 使用 vscode 启动 的 cmd 命令 就是 code .
Vue-cli3.x 自定义脚手架
全局安装了 Vue-cli3 之后 vue的版本就变成了 3.x 版本了
ESLint Standard config 正常选择 就是 基本配置 所以就是这个
Lint on save 就之前的配置 进行保存
future project 这个就是让选择 是否保存为 自己的模板 然后设置名字就好了
最后项目进行安装
-
在 window 系统/用户/sunian 找到隐藏文件 vuerc 然后进行编辑
{ "useTaobaoRegistry": true } 这个是 vue 配置文件 必须一个 属性 或者给一个 空的对象 就可以进行下一步了
然后 进行相关手动配置就可以了。
vue-cli3.x 新出的添加插件的方法
- vue-cli2的时候 可以 通过 npm install 来进行 添加
- 不一样的就是 views 文件夹 和 components 下面的 vue文件~
- 然后 public 下面的 图标 和 index.html 等等
-
vue-cli3.x 是可以在项目中运行
vue add 插件名称
- 然后有点时候 模板会提示 是否替换 模板 use a pre-made template
- use custom theme 是否自己定义模板
- use a-la-carte components? 是否要让其他组件去使用
- use babel/polyfill 是否要使用 babel/polyfill
- 然后就可以 进行 添加到 项目中了
- 如果 装载一个 不会对当前项目结构 有影响的插件 还是推荐 cnpm install 来进行 装载
- 如果 装载的是一个 Ui 库 而且需要对当前的项目 结构 有影响 那就使用 Vue add 来进行安装
Vue-cli3.x 全局环境变量的使用
-
环境变量 是在开发 和 生产环境下 会经常使用到
- 在开发当中使用一个接口 但是在打包上线的时候 会使用线上的一个接口
- 所以这个时候 就会使用到 环境变量的形式 去配置这个东西 了
-
如果 需要创建 环境变量的话 就需要在根路径 下 新建
.env
的文件-
在这个文件里面 可以 进行定义 设置 环境变量
VUE_APP_自定义的名称 = 值; // 前面这个是固定了的 vue_app_ // 这个值也会将 后面的 分号打印出来
-
如果需要将这个环境变量展示出来的话 需要在 引用页面的 script 标签下的 data 当中 需要拿到这个环境变量
export default { data () { return { url : process.env.VUE_APP_URL } } } 然后可以在 template 中调用一下这个 {{ url }}
如果要修改 环境变量的值 就需要重新启动这个项目 才可以更新值
-
-
如果需要创建开发环境的 环境变量的 就需要在项目根目录 下新建
.env.development
的文件- 然后 将两个 变量 都存储 相同的 键
- 如果我们现在在我们的开发环境下 所以 他最新 追求的是
.env.development
的文件 - 所以 首先 获取到的内容 就是
.env.development
的内容
- 如果我们现在在我们的开发环境下 所以 他最新 追求的是
- 但是如果是在非开发环境下的话 获取到的就是
.env
文件下的变量 -
如果是生产环境下的话 就会首先追求
.env.production
文件下的内容- 然后在 运行 npm run build 的时候 会首先 去看
.env.production
文件下的内容 - 如果没有这个文件 就会首先 加载
.env
的内容 - 只有在开发环境下 会先加载
.env.development
的文件
- 然后在 运行 npm run build 的时候 会首先 去看
VUE_APP_
这个是 必须写正确的 如果错误 会去找别的文件下面的变量 进行加载
- 然后 将两个 变量 都存储 相同的 键
Vue-cli3.x 独立运行 .vue 文件 不需要依赖 脚手架
- 运行 单个 .vue 文件 是需要 文件没有进行 关联 别的文件的 前提下 运行的
- 运行 单个 vue 文件的cmd
vue serve .vue的文件名字带后缀
- 首先是先要 cd 到 所在的项目文件夹下面的
- 然后 如果想要 单独运行该文件 需要安装
cnpm i @vue/cli-service-global -g
- 装载完之后 然后运行
vue serve .vue的文件名字带后缀
Vue-cli3.x 图形页面构建项目
- 在 任何路径下 都可以直接运行
vue ui
然后可以在页面中 cd 进行任何目录- 进行 安装 或者 导入项目
- 创建项目
- 项目名称
- 然后 也有 手动 默认等等的插件安装 配置
- 然后 也会让选择项目 之后 会让做一个预设 (这个预设就是下次可以保存的插件配置名称)
- 之后就会 自动创建项目
- 然后里面就会有 插件 依赖 配置 任务 等等
- 任务里面的 serve 运行 就相当于 cnpm run serve 运行一样
- 然后里面可以很直观的看到 插件 依赖 配置一些等等
- 也可以在里面进行添加 插件 搜索 进行安装 配置就可以了
Vue-cli3.x 配置基础的路径
-
在项目的根目录下创建一个
vue.config.js
然后进行如下配置module.exports = { baseUrl : "/", // 根路径 outputDir : "dist", // 构建输出目录 assetsDir : "assets", // 静态资源目录(js,css,img,fonts) LintOnSave : false, // 是否开启 ESLint 保存检测 有效值: true || false || 'error' }
Vue-cli3.x 配置跨域请求
-
继上面这个之后 继续配置
module.exports = { ...LintOnSave... devServer : { open : true, // 如果open设置成为 false 就不会自动打开浏览器 host : "localhost", //真机测试 0.0.0.0 或者 127.0.0.1 port : 8081, // 这个就是修改端口号 https : true, // 这里最好还是 使用 http 所以需要设置成 false hotOnly : false,// 热更新 webpack 也有 如果添加了模块的话 会更好的进行一些配置 proxy : { // 配置跨域 "/api" : { target : "http//localhost:5000/api/", ws : true, changOrigin : true, pathRewrite : { '^/api' : '', // 现在就已经把跨域配置完了 这个好像就是将 ^api 替换 } } } } }
Vue-cli3.x 加载美团数据JSON
-
继上面这个之后 继续配置
// 引入json文件 const goods = require("./data/goods.json"); module.exports = { ...proxy... before (app) { //在服务内部 所有其他中间件之前 提供执行自定义中间件的功能 还可以用来 //配置自定义处理程序 // 这块的地址就应该是 http://localhost:8081/api/goods app.get("/api/goods",(req,res) => { res.json(); // 这样就可以拿到 json 数据了 然后就可以进行相对应的调用 }) } }
VUE2 模块解析
build 模块
- build.js 生产包
- 如果require()导入的是一个函数的话 如果要调用就需要 require('./...')()进行调用
- process.env.NOOE_ENV = ‘production’ 设置开发变量
- until 是工具类 merge(npm包)会继承一个配置
- devtool:config.build.productionSourceMap ? '#source-map' : false,
- 生产包里面不需要进行调试
Vue-cli3 了解 And 项目初始化
安装运行
运行
cnpm i @vue/cli -S
创建项目
vue create init-vue
-
因为项目中 需要运行 vue-cli3 的东西 也由于在原先项目中安装了 vue-cli 2.x 的版本
所以需要 uninstall vue-cli2.x 原先的版本 安装 vue-cli3.x的版本
cnpm uninstall -g vue-cli
cnpm install -g @vue/cli
然后再 创建项目
vue create init-vue
-
或者使用图形化界面来创建和管理项目
vue ui
上述命令会打开一个浏览器窗口,并以图形化界面将你引导至项目创建的流程。
-
创建项目
vue create 项目名称
会让选择默认(default) 还是手动 (Manually)
选择默认的话 一路回车就可以了
手动配置的话 会让选择其选项 空格键 是选择单个 a键是全选
然后选择需要的插件配置 enter就可以进行下一项
vue-router 默认 hash 模式 所以选择默认的 选择了 n 而不是 history 模式
然后会询问 安装 哪一种 css 预处理语言 scss less等等
然后让你选择 自动化代码格式化检测 配合 VSCode 编辑器
Prettier - Code formatter 插件 所以选择最后一个
然后选择 Pick addition lint features
第一个 是 保存就检测
第二个 是 fix 和 commit 的时候检查
Pick a unit testing solution: 选择单元测试解决方案
Mocha + chai
Jest
Mocha 是流行的 js 测试框架之一 通过他添加和运行测试 从而保证代码质量 chai是断言库。都选择
然后会让选择 babel eslint postcss 这些配置文件放哪 一般选择第一个
Where do you prefer placing config for Babel pstcss...?
第一个是 放置独立文件夹 第二个是 放置package.json文件里
再之后 倒数第二行 是问是否将以上这些保存为 未来的项目配置
是的话 下次创建项目 可以选择刚刚配置好的配置 不用再搭配
最后一个是选择名字 再创建的时候 刚刚配置好的 名字 形式出现
-
启动命令
// 1. 进入项目 cd 项目名称 // 或者 cd vue-webpack-demo2 // 2. 安装依赖 npm i // 3. 启动 npm run serve
-
相比 vue-cli 2.x 创建的目录
- vue-cli3.x 的目录 看不见 webpack 的配置
- 启动命令变化 npm run dev 或者 npm start 改变为 npm run serve
- 安装过程的变化 配置可以保存 下次可以再用
-
手动配置 webpack
- 在根目录 下 新建一个 vue.config.js 文件 进行 相关的配置
const path = require('path'); module.exports = { // 基本路径 baseUrl: './', // 输出文件目录 outputDir: 'dist', // eslint-loader 是否在保存的时候检查 lintOnSave: true, // webpack配置 // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md chainWebpack: () => {}, configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { // 为生产环境修改配置... config.mode = 'production'; } else { // 为开发环境修改配置... config.mode = 'development'; } Object.assign(config, { // 开发生产共同配置 resolve: { alias: { '@': path.resolve(__dirname, './src'), '@c': path.resolve(__dirname, './src/components') } } }); }, // 生产环境是否生成 sourceMap 文件 productionSourceMap: true, // css相关配置 css: { // 是否使用css分离插件 ExtractTextPlugin extract: true, // 开启 CSS source maps? sourceMap: false, // css预设器配置项 loaderOptions: {}, // 启用 CSS modules for all css / pre-processor files. modules: false }, // use thread-loader for babel & TS in production build // enabled by default if the machine has more than 1 cores parallel: require('os').cpus().length > 1, // PWA 插件相关配置 // see https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa pwa: {}, // webpack-dev-server 相关配置 devServer: { open: process.platform === 'darwin', host: '0.0.0.0', port: 8080, https: false, hotOnly: false, // proxy: { // // 设置代理 // // proxy all requests starting with /api to jsonplaceholder // 'http://localhost:8080/': { // target: 'http://baidu.com:8080', //真实请求的目标地址 // changeOrigin: true, // pathRewrite: { // '^http://localhost:8080/': '' // } // } // }, before: (app) => {} }, // 第三方插件配置 pluginOptions: { // ... } };
Vue-cli 3.x 和旧版本使用了相同的 vue 命令 所以 vue-cli 2.x 被覆盖了 如果仍要使用旧版本的 vue init 功能
可以全局安装一个 桥接工具
npm i -g @vue/cli-init
vue init webpack my-project
踩坑点
npm 的全局路径被修改了
我都不记得在装什么包的时候修改了 mac 中 npm 的全局路径了,平时 npm 运行各种命令不报错。
全局卸载 vue-cli 命令行:
npm uninstall vue-cli -g;
但是今天全局卸载 vue-cli 的时候一直不成功,搞了一个小时,结果看了一下 npm 的全局路径,才发现路径不对!!!
如果你的 npm 的全局路径也变了,请按如下步骤修改加默认的。
方法一:
原因:npmr 的配置改变了,导致正确的 npmr 不能用。
- 打开终端,切换到根路径
cd
open .npmrc
- 文件里面修改为 prefix=/usr/local
方法二:
npm config set prefix /usr/local //是默认路径 修改了路径会出现错误。
按上面的方法修改完,再全局卸载 vue-cli 果然就成功了。
之前看的一些问题总结的笔记
-
vue里面的 router这两个的区别
router是实例 $route是对象 然后这个对象的方法 实例也都有的吗?
-
vue里面的计算属性和过滤器都有封装作用 那实际应用中哪个比较多应用一些?
计算属性和watch又都会监听data数据的改变 watch做更复杂的操作的话 项目中常用的是那些?
-
vuex 里面的 map辅助函数 和 里面的解构用法 { commit } 这里不太懂...
actions: { incrementAsync ({ commit }) { setTimeout(() => { commit('increment') }, 1000) } }
axios 的封装不太会怎么进行封装(可能会在项目中练习吧 不会的话再问您)
有async就不用 then 方法了吗~
async 和 await 不同的调用加返回 都是什么情况和值
async function(){
// 这个会强制转换成 promise 了
//
}
// await 呢就是将这个 promise 结果转换成别的结果
async/await
Async
-
函数前面的
async
一词意味着一个简单的事情 这个函数总是返回一个promise
如果代码中有return 非Promise
语句 JS 就会自动把这个 value 包装成 promise 的 resolved 值;上面的代码返回resolved值为1的promise,我们可以测试一下 async function f() { return 1 } f().then(alert) // 1 我们也可以显式的返回一个promise,这个将会是同样的结果: async function f() { return Promise.resolve(1) } f().then(alert) // 1
- 所以
async
确保了函数的返回一个Promise
即使其中包含了非promise
但是不仅仅如此,还有另外一个关键词await
只能在async
函数里面使用
- 所以
await
-
只能在 async 函数内部使用
// 只能在async函数内部使用 let value = await promise
关键词
await
可以让 JS 进行等待 知道一个Promise
执行并返回他的结果 JS才会继续往下执行-
以下是一个promise在1s之后resolve的例子:
async function f() { let promise = new Promise((resolve, reject) => { setTimeout(() => resolve('done!'), 1000) }) let result = await promise // 直到promise返回一个resolve值(*) alert(result) // 'done!' } f()
- 函数执行到(*)行会‘暂停’,当promise处理完成后重新恢复运行, resolve的值成了最终的result,所以上面的代码会在1s后输出
'done!'
- 函数执行到(*)行会‘暂停’,当promise处理完成后重新恢复运行, resolve的值成了最终的result,所以上面的代码会在1s后输出
我们强调一下:
await
字面上使得JavaScript等待,直到promise处理完成,-
这只是一个更优雅的得到promise值的语句,它比promise更加容易阅读和书写。
// 不能在常规函数里使用await // 如果我们试图在非async函数里使用await,就会出现一个语法错误: function f() { let promise = Promise.resolve(1) let result = await promise // syntax error }
如果我们忘记了在函数之前放置async,我们就会得到这样一个错误。如上所述,await只能在async函数中工作。
function showAvatar(githubUser) {
return new Promise(function(resolve, reject) {
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
setTimeout(() => {
img.remove();
resolve(githubUser);
}, 3000);
});
}
// 1.我们需要将.then()替换为await
// 2.此外,我们应该让函数变成async,这样await才能够工作
-
await不能工作在顶级作用域 那些刚开始使用await的人们老是忘记这一点,那就是我们不能将await放在代码的顶层,那样是行不通的:
// 顶层代码处syntax error let response = await fetch('/article/promise-chaining/user.json') let user = await response.json()
所以我们需要将await代码包裹在一个async函数中,就像上面的例子一样。
比较理解的 async await
await 后面可以跟任何的JS 表达式。虽然说 await 可以等很多类型的东西,但是它最主要的意图是用来等待 Promise 对象的状态被 resolved。如果await的是 promise对象会造成异步函数停止执行并且等待 promise 的解决,如果等的是正常的表达式则立即执行。 下面上代码
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(' enough sleep~');
}, second);
})
}
function normalFunc() {
console.log('normalFunc');
}
async function awaitDemo() {
await normalFunc();
console.log('something, ~~');
let result = await sleep(2000);
console.log(result);// 两秒之后会被打印出来
}
awaitDemo();
// normalFunc
// VM4036:13 something, ~~
// VM4036:15 enough sleep~
实例中进行说明
-
举例说明 你有三个请求需要发生 第三个请求依赖于第二个请求的结果 第二个请求依赖于第一个请求的结果 若用 Promise 至少需要3个then. 然后现在有 async-await 的实现
//我们仍然使用 setTimeout 来模拟异步请求 function sleep(second, param) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(param); }, second); }) } async function test() { let result1 = await sleep(2000, 'req01'); let result2 = await sleep(1000, 'req02' + result1); let result3 = await sleep(500, 'req03' + result2); console.log(` ${result3} ${result2} ${result1} `); } test(); //req03req02req01 //req02req01 //req01
错误处理
上述代码 好像给的都是 resolve 的情况 那么 reject 的时候我们应该如何处理呢?
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('want to sleep~');
}, second);
})
}
async function errorDemo() {
let result = await sleep(1000);
console.log(result);
}
errorDemo();// VM706:11 Uncaught (in promise) want to sleep~
// 为了处理Promise.reject 的情况我们应该将代码块用 try catch 包裹一下
async function errorDemoSuper() {
try {
let result = await sleep(1000);
console.log(result);
} catch (err) {
console.log(err);
}
}
errorDemoSuper();// want to sleep~
// 有了 try catch 之后我们就能够拿到 Promise.reject 回来的数据了。
小心你的并行处理!!!
对于初学者来说一不小心就将 ajax 的并发请求发成了阻塞式同步的操作了,我就真真切切的在工作中写了这样的代码。 await 若等待的是 promise 就会停止下来
。业务是这样的,我有三个异步请求需要发送,相互没有关联,只是需要当请求都结束后将界面的 loading 清除掉即可。
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('request done! ' + Math.random());
}, second);
})
}
async function bugDemo() {
await sleep(1000);
await sleep(1000);
await sleep(1000);
console.log('clear the loading~');
}
bugDemo();
loading 确实是等待请求都结束完才清除的。 但是 这个请求是一个结束后再发送另外一个的
-
接下来这个是正常的处理 并发请求的过程
async function correctDemo() { let p1 = sleep(1000); let p2 = sleep(1000); let p3 = sleep(1000); await Promise.all([p1, p2, p3]); console.log('clear the loading~'); } correctDemo();// clear the loading~
恩, 完美。看吧~ async-await并不能取代promise.
await in for 循环
最后一点了,await必须在async函数的上下文中的。
// 正常 for 循环
async function forDemo() {
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i ++) {
await arr[i];
}
}
forDemo();//正常输出
// 因为想要炫技把 for循环写成下面这样
async function forBugDemo() {
let arr = [1, 2, 3, 4, 5];
arr.forEach(item => {
await item;
});
}
forBugDemo();// Uncaught SyntaxError: Unexpected identifier
补充
async function timeout() {
return 'hello world'
}
console.log(timeout()); // Promise { 'hello world' }
console.log('虽然在后面,但是我先执行'); // 虽然在后面,但是我先执行
- 原来async 函数返回的是一个promise 对象,如果要获取到promise 返回值,我们应该用then 方法, 继续修改代码
async function timeout() {
return 'hello world'
}
timeout().then(result => {
console.log(result);
})
console.log('虽然在后面,但是我先执行');
// 虽然在后面,但是我先执行 hello world
-
async 函数内部的实现原理 :
- 如果async 函数中有返回一个值 ,当调用该函数时,内部会调用Promise.solve() 方法把它转化成一个promise 对象作为返回,但如果timeout 函数内部抛出错误呢? 那么就会调用Promise.reject() 返回一个promise 对象, 这时修改一下timeout 函数
async function timeout(flag) { if (flag) { return 'hello world' } else { throw 'my god, failure' } } console.log(timeout(true)) // 调用Promise.resolve() 返回promise 对象。hello world console.log(timeout(false)); // 调用Promise.reject() 返回promise 对象。my god, failure
如果函数内部抛出错误, promise 对象有一个catch 方法进行捕获。
timeout(false).catch(err => { console.log(err) })
Promise then 就是变成同步调用?
箭头函数的this指向问题