Just a blog
reinerlau1 / blog Goto Github PK
View Code? Open in Web Editor NEWJust a blog
License: MIT License
Just a blog
License: MIT License
yarn add webpack-dev-server -D
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1024 * 3,
esModule: false,
},
},
type: "javascript/auto",
},
],
},
+ devServer: {
+ open: true,
+ port: 8080,
+ },
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
],
};
yarn webpack-dev-server
都是用来引用外部的资源
webpack
在打包时自动添加前缀yarn add autoprefixer postcss-loader postcss -D
autoprefixer
属于postcss
工具的添加前缀的插件
有两种配置方式:
第一种:直接在webpack.config.js
中配置
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
+ {
+ loader: 'postcss-loader',
+ options: {
+ postcssOptions: {
+ plugins: [require('autoprefixer')]
+ }
+ }
+ }
]
}
]
}
}
第二种:独立在postcss.config.js
中配置
webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
+ 'postcss-loader'
]
}
]
}
}
postcss.config.js
module.exports = {
plugins: [require('autoprefixer')],
}
不配置插件就不知道按照什么样的规则进行前缀补全
package.json
// 这里的意思表示目标浏览器为ie浏览器,并需要兼容到ie8以上
"browserslist": ["ie > 8"]
选择器 | 格式 | 权重 |
---|---|---|
id选择器 | #id | 100 |
类选择器 | .class | 10 |
伪类选择器 | li:last-child | 10 |
属性选择器 | a[ref=‘eee’] | 10 |
标签选择器 | div | 1 |
伪元素选择器 | li:after | 1 |
相邻兄弟选择器 | h1+p | 0 |
子选择器 | ul>li | 0 |
后代选择器 | ul a | 0 |
通配符选择器 | * | 0 |
测试打包效果的html文件是我们自己创建的,我们需要html-webpack-plugin
自动生成html文件并自动引入dist
下的依赖
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
+ const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
+ new HtmlWebpackPlugin({
+ template: './src/index.html'
+ })
]
}
在src
下创建作为模板的html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div class="box"></div>
</body>
</html>
mkdir app
package.json
文件npm init -y
yarn add webpack webpack-cli -D
src
文件夹src
下创建index.js
index.js
下添加代码console.log('hello webpack')
package.json
中配置scripts
字段"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack"
}
yarn start
命令,会得到以下结果上面的测试中,webpack
是如何知道要对src
下的index.js
文件进行打包的?其实刚开始初始化项目时会有一个默认的webpack
配置,默认配置如下:
const path = require('path')
module.exports = {
extry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
}
}
一目了然,如果我们需要覆盖默认的配置,需要创建webpack.config.js
文件或者执行命令指定配置文件
webpack --config xxx.js
chunk
:指代码块,一个chunk可能由多个模块组合而成,也用于代码合并与分割(这里的合并分割主要指指纹策略的判断),指纹策略简单来说就是文件名后的hashbundle
:资源经过webpack流程解析编译后最终输出的成果文件(一个.js格式的文件,也就是我们的output文件)entry
:文件打包的入口,webpack会根据entry递归的去寻找依赖,每个依赖都将被它处理,最后打包到集合文件中output
:配置打包输出的位置、文件名等loader
:默认情况下,webpack仅支持js和json文件,通过loader,可以让它解析其他类型的文件。理论上只要有相应的loader,webpack可以处理任何类型的文件plugin
:loader主要的职责是让webpack认识更多的文件类型,而plugin的职责则是让其可以控制构建流程,从而执行一些特殊的任务。插件的功能非常强大,可以完成各种各样的任务mode
:目标环境,不用的目标环境会影响webpack打包时的决策
production
:码进行压缩等一系列优化操作development
:有利于热更新的处理,识别哪个模块变化代none
:什么都不做,打包时会有提示警告module.exports = function (source) {
return source.replace('hello webpack', "你好呀,webpack!")
}
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1024 * 3,
esModule: false,
},
},
type: "javascript/auto",
},
+ {
+ test: /\.js$/,
+ use: path.resolve(__dirname, "./loader/replaceLoader.js"),
+ },
],
},
devServer: {
open: true,
port: 8080,
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
],
};
这两个属性都是让元素隐藏,不可见
app.js
文件var msg = 'Hello World';
console.log(msg);
大多数的情况是项目很复杂,文件很多,但入口文件只有一个,但此时没有打开入口文件,这时按F5是无法进入调试模式,因为VSCode根本无法识别从哪个文件进入调试模式,所以我们需要配置默认需要调试的入口文件
我们通常运行scripts
中的脚本执行项目,我们可以点击Debug
选择要执行的脚本进入调试模式(记得打断点)
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const HtmlPlugin = require("./plugin/htmlPlugin");
+ const Webpack = require("webpack");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [
- MiniCssExtractPlugin.loader
+ "style-loader",
"css-loader",
"postcss-loader"
],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1024 * 3,
esModule: false,
},
},
type: "javascript/auto",
},
{
test: /\.js$/,
use: path.resolve(__dirname, "./loader/replaceLoader.js"),
},
],
},
devServer: {
open: true,
port: 8080,
+ hot: true
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
new HtmlPlugin(),
+ new Webpack.HotModuleReplacementPlugin(),
],
};
都是用来引用外部CSS
两者相互结合使用
第一种
假如你是用vue-cli
创建的项目,在创建时可以直接勾选Jest
配置,但如果你没有勾选而是之后添加的,那么你可以选择添加unit-jest
插件,该插件会帮你一次性安装需要的依赖并且配置好相关文件同时生成一个demo测试文件,之后就是愉快使用Jest
和Vue-Test-Utils
编写测试文件
vue add @vue/unit-jest
第二种
需要手动安装各种依赖并且自行配置
yarn add jest @vue/test-utils -D
babel-jest vue-jest [email protected]
bebel-jest
用于处理js文件vue-jest
用于处理vue文件[email protected]
是因为Jest
不认识Babel7
,需要安装该依赖防止报错package.json
或者jest.config.js
上配置都可以,这里以jest.config.js
为例module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'], // 告诉 Jest 处理 `*.vue` 文件
transform: {
'.*\\.(vue)$': 'vue-jest', // 用 `vue-jest` 处理 `*.vue` 文件
'.*\\.(js)$': 'babel-jest' // 用 `babel-jest` 处理 js
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1' // 支持@别名
}
}
import { shallowMount } from '@vue/test-utils'
import HelloWord from '@/components/HelloWord.vue'
describe('HelloWord.vue', () => {
it('renders props.msg when passed', () => {
const wrapper = shallowMount(HelloWord, {
propsData: { title: 'new message' }
})
expect(wrapper.text()).toMatch('new message')
})
})
可以先在package.json
中添加命令方便运行
"scripts": {
"test": "jest"
}
yarn test
运行命令后Jest
会默认查找当前项目下的__tests__
目录所有以.spec.js
或者.test.js
后缀的测试文件并运行测试,当然查找目录可以自行在jest.config.js
中配置
修改命令即可
"scripts": {
"test": "jest --coverage"
}
该命令执行后还会生成coverage
文件夹,里面有一个index.html
文件,打开可以通过网页查看覆盖率
假如要收集整个项目所有文件的测试覆盖率,那么可以通过配置jest.config.js
实现
module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'],
transform: {
'.*\\.(vue)$': 'vue-jest',
'.*\\.(js)$': 'babel-jest'
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1'
},
+ collectCoverage: true,
+ collectCoverageFrom: ['**/*.{js,vue}', '!**/node_modules/**']
}
这是因为我的项目引入了ant-design-vue
这个第三方组件,Jest
在node
环境下运行时不认识这些第三方组件,需要我们注册组件,这里不推荐使用Vue.use(VueRouter),因为会污染全局的Vue
修改测试文件
import {
+ createLocalVue
shallowMount
} from '@vue/test-utils'
+ const localVue = createLocalVue()
+ import Antd from 'ant-design-vue'
+ localVue.use(Antd)
import HelloWord from '@/components/HelloWord.vue'
describe('HelloWord.vue', () => {
it('renders props.msg when passed', () => {
const wrapper = shallowMount(HelloWord, {
propsData: { title: 'new message' }
})
expect(wrapper.text()).toMatch('new message')
})
})
通过createLocalVue
创建了一个localVue
,相当于import Vue
;然后localVue.use
告诉Vue
来使用Antd
,和Vue.use
有着相同的作用
我们需要在不同屏幕宽度情况下显示不同的图片,这时候我们就需要picture
标签,同时还要结合source
标签
<picture>
<source media="(max-width: 799px)" srcset="img1.jpg" />
<source media="(min-width: 800px)" srcset="img2.jpg" />
<img src="img1.jpg" alt="test" />
</picture>
799px
以下时显示img1.jpg
这张图片800px
以上时显示img2.jpg
这张图片media
媒体查询的情况下默认显示img1.jpg
这张图片srcset
指定多张不同分辨率的图片特点
优缺点
每次打包dist文件夹的内容会被覆盖,但是如果下次打包出来的文件名不同,那旧的打包文件还会存在,这是我们不想要的,我们需要clean-webpack-plugin
清空文件夹
yarn add clean-webpack-plugin -D
const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
+ const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: './src/index.html'
}),
+ new CleanWebpackPlugin()
]
}
常用于编写命令行工具
"bin": {
"test": "./index.js"
}
test
命令就是运行index.js
这个文件test
命令映射到环境变量PATH
下,也就是该命令可以在任意地方执行test
命令映射到node_modules/.bin/
目录下到这里我已经可以使用如下命令执行脚本
node node_modules/.bin/test
但这样一点都不简便,如果加上 node 前缀,就需要指定test
的路径node_modules/.bin
,否则node test
会去查找当前路径下的index.js
,这样肯定是不对的
我们可以在要执行文件的第一行添加以下代码
#!/usr/bin/env node
这样我只需要简单地执行test
就可以
test
在封装第三方组件时,经常会遇到的问题是要通过封装的组件去使用第三方组件自身的属性和事件
我们封装了一个ElementUI
组件的Input
组件叫MyInput
<template>
<div>
<el-input v-model="input"></el-input>
</div>
</template>
<script>
export default {
data() {
return {
input: '',
}
}
}
</script>
假如我们需要给MyInput
组件添加disabled
属性来禁用下拉框,一般情况下会这样
<template>
<div>
<el-input
v-model="input"
+ :disabled="disabled"
></el-input>
</div>
</template>
<script>
export default {
+ props: {
+ disabled: {
+ type: Boolean,
+ default: false,
+ },
+ },
data() {
return {
input: ''
}
}
}
</script>
假如过一段时间后要使用Input
的其他,那么这样一个个prop
传进入的操作将会非常繁琐而且可读性差,这时我们可以用$attrs
代替,这个属性可以获取组件绑定的attribute
。这样我们只需要直接在封装的组件上使用第三方组件的属性
<template>
<div>
<el-input
v-model="input"
- :disabled="disabled"
+ v-bind="$attrs"
></el-input>
</div>
</template>
<script>
export default {
+ inheritAttrs: false
- props: {
- disabled: {
- type: Boolean,
- default: false,
- },
- },
data() {
return {
input: ''
}
}
}
</script>
要注意的是,我们这里要设置inheritAttrs
为false
时,v-bind="$attrs"
才能生效
同理,使用第三方组件的事件可以使用$listeners
<template>
<div>
<el-input
v-model="input"
+ v-bind="$attrs"
+ v-on="$listeners"
></el-input>
</div>
</template>
<script>
export default {
data() {
return {
input: ''
}
}
}
</script>
JSDoc
可以让我们通过代码注释,让 VSCode 为我们自己的代码提供提示,只需要在函数上方输入/**
能补全函数相关的注释,比如传参类型,返回值类型等,其实就是块注释,更多用法参考文档
当我们使用npm install
下载了第三方模块后,一般情况下使用时会有智能提示,这是什么原理呢?
原来像lodash
这样的第三方模块在发布到 npm 库上时一般也会发布一个d.ts
文件(按住 ctrl 点击或者按 F12 该模块的函数可以跳转对应的d.ts
文件位置),这个文件为模块里的函数和对象提供了类型建议
d.ts
文件,如果有,直接使用d.ts
文件,如果有,直接使用,因为我们可以自行编写d.ts
文件d.ts
文件,也就是模块是否带有对应的@types/
前缀的模块,如果有,VSCode 会自行下载使用,不需要我们手动下载我们可以在这个配置文件中手动设置需要提示的模块,即使该模块没有下载到本地
{
"typeAcquisition": {
"include": ["jquery"]
}
}
ts-check
可以让我们为某个js文件启动类型检查,需要在第一行添加@ts-check
注释,如果没有遵守类型,VSCode可以提示错误
特性
常见标签
<a></a>
<b></b>
<span></span>
<img></img>
<input></input>
<select></select>
<strong></strong>
vue和react的组件测试本质也属于单元测试或者集成测试
npm init
用的最多的地方就是初始化一个package.json
文件
当这段命令后加上<initializer>
,也就是npm init <initializer>
时,会在npm库上寻找名为create-<initializer>
的npm包,并用npx #50 临时安装这个包,然后执行其package.json
中bin
属性对应的脚本,会创建或更新package.json
并运行一些与初始化相关的操作
命令 | 等同 |
---|---|
npm init foo | npx create-foo |
npm init @usr/foo | npx @usr/create-foo |
npm init @usr | npx @usr/create |
script
字段GitHub
源码属性值 | 作用 |
---|---|
none | 元素不显示,并且从文档流中移除 |
block | 默认宽度为父元素宽度,可设置宽高,换行显示 |
inline | 默认宽度为内容宽度,不可设置宽高,同行显示 |
inline-block | 默认宽度为内容宽度,可设置宽高,同行显示 |
list-item | 与block相同,同时有列表标记 |
table | 以块级表格显示 |
inherit | 从父元素继承display属性 |
组件名应该始终是多个单词,应该始终是PascalCase
,避免跟现有的以及未来的HTML元素冲突,因为所有HTML元素名称都是单个单词
export default {
name: 'ToDoList',
.....
}
camelCase
,因为在JavaScript中更自然kebab-case
,在HTML中更自然<MyComponent my-name="reiner">
export default {
name: 'MyComponent',
// ...
props: {
myName: {
type: String,
required: true,
}
}
}
Vue Router Path
命名采用kebab-case
,用snake
或者camelCase
会被当成一个单词,搜索引擎无法区分语义
{
path: '/user-info',
name: 'UserInfo',
component: UserInfo
}
PascalCase
的kebab-case
的<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在DOM模板中 -->
<my-component></my-component>
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>
<!-- 在DOM模板中 -->
<my-component></my-component>
camelCase
,let tableTitle = 'loginTabel',
let mySchool = '我的学校'
const MAX_COUNT = 10
const URL = 'http://test.host.com'
camelCase
// 1、普通情况下,使用动词 + 名词形式
// bad
go、nextPage、show、open、login
// good
jumpPage、openCarInfoDialog
// 2、请求数据方法,以 data 结尾
// bad
takeData、confirmData、getList、postForm
// good
getListData、postFormData
// 3、单个动词的情况
init、refresh
动词 | 含义 | 返回值 |
---|---|---|
can | 判断是否可以执行某个动作 | 函数返回一个布尔值。true:可执行;false:不可执行 |
has | 判断是否含有某个值 | 函数返回一个值。true:含有此值;false:不含有此值 |
is | 判断是否为某个值 | 函数返回一个布尔值。true:为某个值;false:不为某个值 |
get | 获取某个值 | 函数返回一个非布尔值 |
set | 设置某个值 | 无返回值,返回是否设置成功或者返回链式对象 |
始终使用kebab-case
形式,且遵守on
+动词
的形式
<template>
<div
@click.native.stop="handleItemClick()"
@mouseenter.native.stop="handleItemHover()">
</div>
</template>
<script>
export default {
methods: {
handleItemClick () {
//...
},
handleItemHover () {
//...
}
}
}
</script>
全部采用小写方式,已短横线分隔,例my-project-name
有复数结构时,要采用复数命名法,例docs
、assets
全部采用小写方式,优先选择单个单词命名,多个单词命名以下划线分隔,例banner_sina.gif
全部采用小写方式,优先选择单个单词命名,多个单词命名以下划线分隔,例error_report.html
全部采用小写方式,优先选择单个单词命名,多个单词命名以短横线分隔,例date-picker.scss
全部采用小写方式,优先选择单个单词命名,多个单词命名以短横线分隔,例index.js
、account-modle.js
快速记忆方法:静态文件下划线,编译文件短横线
我们常常要将一个对象的属性都作为prop传入组件中,但这样会导致可读性降低,这时我们可以使用v-bind
一次性传入
params: {
id: 1,
name: 'vue'
}
优化前
<MyComponent :id="params.id" :name="params.name" />
优化后
<MyComponent v-bind="params" />
img
标签yarn add html-loader url-loader file-loader -D
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
+ {
+ test: /\.(png|jpe?g|gif)$/,
+ use: {
+ loader: "url-loader",
+ options: {
+ name: "[name].[ext]",
+ limit: 1024 * 3,
+ },
+ },
+ },
+ {
+ test: /\.html$/,
+ loader: "html-loader",
+ options: {
+ esModule: false,
+ },
+ },
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
],
};
如果不配置
esModule: false
,引入的图片的看不了
index.html
中引入图片<img src="./avator.jpg" />
import imgSrc from "./avator.jpg";
const img = document.getElementsByTagName("img")[0];
img.src = imgSrc;
html引入图片
配置的基础减少html-loader
的配置.box {
display: flex;
width: 100px;
height: 100px;
background-color: #000;
background-image: url(./avator.jpg);
}
html
引入和js
引入稍有不同const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1024 * 3,
+ esModule: false,
},
},
+ type: "javascript/auto",
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
],
};
假设你已经使用vue-cli
创建了一个vue
项目但没有勾选单元测试的相关配置,那么可以跟着我安装需要工具依赖
yarn add @vue/cli-plugin-unit-jest @testing-library/vue @testing-library/jest-dom -D
vue-cli
的插件,底层就是Jest
测试框架用于运行测试和预设配置vue
相关的测试API,比如加载组件什么的,底层也是vue test utils
Jest
本身没有对DOM相关断言的方法,需要这个依赖对其进行扩展想要Jest
能够识别.vue
文件必须在jest.config.js
中进行相关配置
module.exports = {
moduleFileExtensions: ['js', 'json', 'vue'], // 告诉 Jest 处理 `*.vue` 文件
transform: {
'.*\\.(vue)$': 'vue-jest', // 用 `vue-jest` 处理 `*.vue` 文件
'.*\\.(js)$': 'babel-jest' // 用 `babel-jest` 处理 js
},
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/src/$1' // 支持@别名
}
}
但是我们下载的@vue/cli-plugin-unit-jest
已经包含了预设的配置,我们只需要在jest.config.js
中进行以下配置
module.exports = {
preset: "@vue/cli-plugin-unit-jest"
};
同时我们要在package.json
中配置执行测试的命令
"scripts": {
"test": "vue-cli-service test:unit --coverage"
},
--coverage
属于Jest
命令行的可选配置,表示显示覆盖率在__tests__
目录下或者tests/unit
目录下新建测试文件,测试文件以.spec.js
或者.test.js
后缀
import "@testing-library/jest-dom";
import { render } from "@testing-library/vue";
import HelloWorld from "@/components/HelloWorld.vue";
describe("HelloWorld.vue", () => {
it("renders props.msg when passed", () => {
const msg = "new message";
const { getByText } = render(HelloWorld, {
props: { msg },
});
expect(getByText(msg)).toBeInTheDocument();
});
});
关于其中具体语法请参考vue-testing-library和jest
yarn test
报错1
FAIL src/components/UserList.spec.js
● Test suite failed to run
ReferenceError: [BABEL] unknown: Unknown option: C:\Users\drumcoder\app\node_modules\@vue\cli-plugin-babel\preset.js.overrides.
Check out http://babeljs.io/docs/usage/options/ for more information about options.
A common cause of this error is the presence of a configuration options object without the corresponding preset name. Example:
Invalid:
`{ presets: [{option: value}] }`
Valid:
`{ presets: [['presetName', {option: value}]] }`
For more detailed information on preset configuration, please see https://babeljs.io/docs/en/plugins#pluginpresets-options.
解决办法
yarn add babel-core@^7.0.0-bridge.0 -D
<img
srcset="128px.jpg 128w, 256px.jpg 256w, 512px.jpg 512w"
sizes="(max-width: 128px) 128px,(max-width: 256px) 256px,128px"
src="128px.jpg"
/>
srcset
表示浏览器可以选择显示的图片,上面引用了三种相同内容不同尺寸的图片,不同图片路径用逗号隔开w
值表示在img
元素的宽度在该值或者该值以下时显示该值对应的图片,与对应图片隔一个空格,比如img
元素宽度在 128px 或者 128px 以下时会选择加载 128w 对应的图片,也就是128px.jpg
sizes
表示通过媒体查询浏览器在不同屏幕下,浏览器给予img
元素不同的插槽大小,也就是屏幕宽度为 128px 以下时,img
元素的最大宽度为 128px,最后一个为没有对应的媒体查询时,默认的插槽大小还是上面的例子,电脑上打开浏览器,可以看到默认加载的是128px.jpg
,因为电脑屏幕宽度远超与 128px
和 256px
,也就是触发了sizes
默认的媒体查询,也就是128px
,此时浏览器能够给予img
元素的最大宽度为128px
,此时浏览器会优先选择小于或者等于128w
对应的图片
接下来我们切换浏览器到响应式模拟手机设备,可以看到如果我们在128px
下看到的是256px.jpg
这张图片,你可能会好奇等于或者小于128px
不是应该加载128px.jpg
吗,这是因为设备像素比
的存在,一般在手机设备下,手机上的1px
等于电脑上的2px
,这里就不拓展了,总而言之,我们要模拟的屏幕宽度基础乘以 2,也就是256px
,属于等于或者小于256w
的范围,也就加载了256px.jpg
这张图片
同理,如果我们将屏幕宽度调到比128px
大,比256px
小的情况下,会选择加载512px.jpg
这张图片
这里有个注意点,当我们在电脑上模拟时,浏览器有一个缓存机制就是一旦选择加载了大分辨率图片则不管你怎么调整屏幕大小,浏览器都不会重新切换成小分辨率图片,当然正常情况在手机上不可能像这样随意调整屏幕大小,只会加载首次加载时最适合当前屏幕的图片,所以不用担心这个问题
srcset
还有根据屏幕分辨率加载不同分辨率的图片,不过好像现在用的比较少,有兴趣的可以去了解一下picture
元素和source
元素,下篇文章讲解文件拓展名为.vue
的单文件组件
,命名应该始终是单词大写
(PsascalCase)
components/
|- MyComponent.vue
以The
前缀命名
components/
| - TheHeading.vue
| - TheSiderbar.vue
以Base
前缀命名
components/
| - BaseButton.vue
| - BaseTable.vue
data
、prop
以Custom
前缀命名
components/
| - CustomCard.vue
和父组件紧密耦合的子组件应该以父组件作为前缀命名。因为编辑器通常会按字母顺序组件文件,所以这样做可以把相关联的文件排在一起
components/
| - TodoList.vue
| - TodoListItem.vue
| - TodoListItemButton.vue
如下面用于搜索和设置功能的组件
components/
| - SearchButtonClear.vue
| - SearchButtonRun.vue
| - SearchInputQuery.vue
| - SearchInputExcludeGlob.vue
| - SettingsCheckboxTerms.vue
| - SettingsCheckboxLaunchOnStartup.vue
能不用缩写就不要缩写
随着项目的增大,我们不想把那么多的样式都放在style标签中,我们想用link标签引入,这时我们就需要使用mini-css-extract-plugin
yarn add mini-css-extract-plugin -D
const path = require('path')
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [
- 'style-loader'
+ MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
]
},
+ plugins: [
+ new MiniCssExtractPlugin({
+ filename: "css/[name].css"
+ })
+ ]
}
title
只表示是个标题h1
表示层次明确的标题,对页面信息的抓取有很大的影响我们知道webpack
默认只能打包JS文件和JSON文件,打包以外文件需要相应的loader
支持
.box {
width: 100px;
height: 100px;
background-color: #000;
}
import "./index.css";
console.log("hello webpack");
yarn add css-loader -D
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: "css-loader"
}
]
}
}
可以看到CSS代码被打包进最终的bundle文件中
注意:此时创建一个html文件,引入打包出来的bundle文件,打开页面是看不到任何效果的,因为css代码还在js代码中,我们需要style-loader
将我们的css代码放进style标签中
yarn add style-loader -D
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
- use: "css-loader",
+ use: ['style-loader', 'css-loader']
},
],
},
};
注意:当对一种文件进行多种处理时,多个loader
用数组引入,同时执行顺序是从右往左执行,要讲究loader
的顺序,否则可能报错
label
用来定义表单控件的关系label
标签时,浏览器会自动将焦点转到和label
标签相关的表单控件上双向绑定实现原理由Object.defineProperty
改为Proxy
Object.defineProperty的缺点
Proxy的基本用法
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
},
set:function(){ },
deleteProperty:function(){ }
// ...13个配置项
};
const p = new Proxy({}, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b); // 1, undefined
console.log('c' in p, p.c); // false, 37
// ----------------------------------------------------------
let numbers = [0, 1, 2];
numbers = new Proxy(numbers, {
get(target, prop) {
if (prop in target) {
return target[prop];
} else {
return 0; // 默认值
}
}
});
console.log( numbers[1] ); // 1
console.log( numbers[123] ); // 0(没有这个数组项)
Proxy解决的问题
在Vue2
中规定一个vue组件
只能有一个根节点,而Vue3
中多个节点会被包裹在Fragment
元素中,该元素不会在DOM数中被渲染
Vue2
中组件emit事件不需要提前定义,Vue3
中需要
<template>
<div>
<p>{{ text }}</p>
<button v-on:click="$emit('accepted')">OK</button>
</div>
</template>
<script>
export default {
props: ['text'],
emits: ['accepted']
}
</script>
emits
不仅可以接收数组,还可以接收对象,用于验证函数
<template>
<div>
<p>{{ text }}</p>
<button v-on:click="$emit('accepted', text)">OK</button>
</div>
</template>
<script>
export default {
props: ['text'],
emits: {
accepted: function(payload){
if(payload){
return true
}else{
console.log('text不能为空')
return false
}
}
}
}
</script>
单个v-model
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
emits: ['update:firstName', 'update:lastName'],
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName', $event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName', $event.target.value)">
`
})
Vue2
采用的是Options API
编写方式,如下:
export default {
props: {},
data() {
return {};
},
watch: {},
computed: {},
methods: {},
};
Options API的缺点
mixins
,但那也造成命名冲突,来源不清晰的问题Composition API的用法
官方文档写的挺清楚的
beforeCreate
和created
改成setup
on
前缀script
标签引入到页面,一个文件相当于一个模块,并且还要按顺序引入,不然容易导致变量丢失等问题Node.js
的出现和发展,借助Node.js
可以对文件操作的能力,诞生了如gulp
,grunt
等可以为我们打包js的打包工具loader
、plugin
、热更新
等概念的出现,使webpack
的功能不再仅仅是打包js那么简单webpack
本身只能打包js和json格式的文件,但实际项目中我们还有css
、scss
、png
、ts
等其他文件,这时我们就需要使用loader
来让它正确打包loader
就是处理编译js和json以外的文件时用的在webpack
打包构建的过程中,有时我们需要plugin
在这个过程中的某个时机
做些特殊处理
来改变最终打包的结果
postcss
本身只是作为一个平台,真正发挥转换作用的是这个平台上的各种插件
babel
本身只是作为一个平台,真正发挥转换作用的是这个平台上的各种插件
或者说预设
babel的核心库,所有的核心api都在这个库里,这些api可供babel-loader调用
插件的集合,包含所有es6转化为es5的规则
@babel/preset-env
只是提供了语法转换的规则,但是它并不能弥补浏览器缺失的一些新的功能,如一些内置的方法和对象,如Promise,Array.from等,此时就需要polyfill
来做js的垫片,弥补低版本浏览器缺失的这些新功能
JavaScript标准库的polyfill
,而且它可以实现按需加载。使用@babel/preset-env
的时候可以配置core-js
的版本和core-js
的引入方式 @babel/polyfill
依赖core-js
browserslist
应用于babel
、postcss
等工具当中browserslist
可以在package.json
文件配置,也可以单出写一个.browserslistrc
文件进行配置browserslistrc
中的配置,如果没有发现.browserslistrc
文件,则会去package.json
中查找代码块(一个js模块)
多个chunk
的组合
class HtmlPlugin {
constructor (options) {
}
apply(compiler) {
compiler.hooks.emit.tap('HtmlPlugin', (compolation) => {
const content = '<html><body>fake html</body></html>'
compolation.assets['fake.html'] = {
source: function () {
return content
},
size: function () {
return content.length
}
}
})
}
}
module.exports = HtmlPlugin
plugin
目的是输出一个fake.html
文件const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
+ const HtmlPlugin = require("./plugin/htmlPlugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "./dist"),
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 1024 * 3,
esModule: false,
},
},
type: "javascript/auto",
},
{
test: /\.js$/,
use: path.resolve(__dirname, "./loader/replaceLoader.js"),
},
],
},
devServer: {
open: true,
port: 8080,
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new HtmlWebpackPlugin({
template: "./src/index.html",
}),
new CleanWebpackPlugin(),
+ new HtmlPlugin(),
],
};
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.