Giter VIP home page Giter VIP logo

blog's Introduction

Blog

Just a blog

blog's People

Contributors

reinerlau1 avatar

Watchers

 avatar

blog's Issues

Webpack之启动本地服务

安装依赖

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

宏任务和微任务的区别

宏任务

  • script 脚本的执行
  • setTimeout ,setInterval ,setImmediate 一类的定时事件
  • I/O 操作
  • UI 渲染

Webpack之CSS添加兼容性前缀

需求

  • css3在浏览器中会存在兼容性问题,我们可以通过给属性加上前缀来解决该问题
  • 我们需要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"]

效果

image

CSS 选择器及其优先级

选择器权重

选择器 格式 权重
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

Webpack之生成html

需求

测试打包效果的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>

效果

image

如何搭建Webpack项目

如何搭建Webpack项目

初始化

  1. 新建文件夹
mkdir app
  1. 初始化package.json文件
npm init -y

安装依赖

yarn add webpack webpack-cli -D

测试一下

  1. 在根目录下创建src文件夹
  2. src下创建index.js
  3. index.js下添加代码
console.log('hello webpack')
  1. package.json中配置scripts字段
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack"
}
  1. 执行yarn start命令,会得到以下结果
  • 根目录下出现一个dist文件夹,文件夹内是一个main.js文件,内容是打包编译后的代码
  • 同时命令行出现了警告,就是说让我们配置mode字段
    image

webpack的零配置

上面的测试中,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可能由多个模块组合而成,也用于代码合并与分割(这里的合并分割主要指指纹策略的判断),指纹策略简单来说就是文件名后的hash
  • bundle:资源经过webpack流程解析编译后最终输出的成果文件(一个.js格式的文件,也就是我们的output文件)
  • entry:文件打包的入口,webpack会根据entry递归的去寻找依赖,每个依赖都将被它处理,最后打包到集合文件中
  • output:配置打包输出的位置、文件名等
  • loader:默认情况下,webpack仅支持js和json文件,通过loader,可以让它解析其他类型的文件。理论上只要有相应的loader,webpack可以处理任何类型的文件
  • plugin:loader主要的职责是让webpack认识更多的文件类型,而plugin的职责则是让其可以控制构建流程,从而执行一些特殊的任务。插件的功能非常强大,可以完成各种各样的任务
  • mode:目标环境,不用的目标环境会影响webpack打包时的决策
    • production:码进行压缩等一系列优化操作
    • development:有利于热更新的处理,识别哪个模块变化代
    • none:什么都不做,打包时会有提示警告

Webpack之实现一个loader

编写一个函数

module.exports = function (source) {
	return source.replace('hello webpack', "你好呀,webpack!")
}
  • loader是一个函数
  • 不能使用箭头函数,因为要用到上下文的this
  • source接收到的是待处理的文件源码
  • return处理后的文件源码,也是下一个loader接收到的文件源码

配置loader

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(),
  ],
};

效果

image

如何在VSCode中调试Node.js

如何在VSCode中调试Node.js

单文件调试

  1. 首先创建app.js文件
var msg = 'Hello World';
console.log(msg);
  1. 在你想要的行数上点击行数左边空白位置或者按F9打上红色的断点
    image

  2. 按F5进入调试模式,假如是第一次进入会让你选择模式,选择Node.js模式就好,一般情况打开了哪个文件才会进入那个文件的调试模式
    image

调试按钮

  • 继续(F5): 点击后代码会直接执行到下一个断点所在位置,如果没有下一个断点,则认为本次代码执行完成。
  • 单步跳过(F10):点击后会跳到当前代码下一行继续执行,不会进入到函数内部。
  • 单步调试(F11):点击后进入到当前函数的内部调试,比如在 fn 这一行中执行单步调试,会进入到 fn 函数内部进行调试。
  • 单步跳出(Shift + F11):点击后跳出当前调试的函数,与单步调试对应。
  • 重启(Ctrl + Shift + F5):顾名思义。
  • 断开链接(Shift + F5):顾名思义。

调试配置

大多数的情况是项目很复杂,文件很多,但入口文件只有一个,但此时没有打开入口文件,这时按F5是无法进入调试模式,因为VSCode根本无法识别从哪个文件进入调试模式,所以我们需要配置默认需要调试的入口文件

  1. 创建launch.json文件,选择Node.js模式
    image
  2. 创建的launch.json文件中,type代表调试模式,program指定要调试的文件,${file}代表当前打开的文件
    image

package.json

我们通常运行scripts中的脚本执行项目,我们可以点击Debug选择要执行的脚本进入调试模式(记得打断点)
image

JavaScript Debug Terminal

打开Debug终端执行脚本命令同样可以进入调试模式
image

开发企业级Vue3项目脚手架需要的东西

需要的工具

  • Nodejs
  • npm
  • VSCode
  • Volar
  • Vue 3 snippets
  • Chrome
  • Vue devtools

步骤

初始化Vite项目

配置Typescript

约束代码风格

  • eslint
  • prettier
  • husky
  • lint-staged
  • mrm

配置 css 预处理器

  • scss
  • sass
  • less
  • stylus

配置路由

  • vue-router

请求封装

  • axios
  • VueRequest

状态管理

  • pinia
  • vuex

环境变量配置

组件库

  • Naive UI

基础配置

  • 代理
  • 生产环境去除 console debugger

常用插件

  • @vitejs/plugin-vue
  • @vitejs/plugin-vue-jsx
  • @vitejs/plugin-legacy
  • unplugin-vue-components
  • vite-plugin-compression

hooks库

  • VueUse

mock模拟数据

  • mockjs
  • fakerjs

单元测试

  • jest
  • mocha
  • testing libary
  • vue test utils

Webpack之热模块替换

需求

  • 启动项目本地服务
  • 修改了一个.css文件的内容
  • 浏览器不刷新使修改的内容生效

配置

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(),
  ],
};

Vue Test Utils + Jest给vue项目添加单元测试

必须知道的概念

  • Jest:是用来运行测试的测试框架,自带断言库
  • Vue-Test-Utils:针对测试vue提供了一系列测试API,方便去编写测试文件

两者相互结合使用

配置

第一种

假如你是用vue-cli创建的项目,在创建时可以直接勾选Jest配置,但如果你没有勾选而是之后添加的,那么你可以选择添加unit-jest插件,该插件会帮你一次性安装需要的依赖并且配置好相关文件同时生成一个demo测试文件,之后就是愉快使用JestVue-Test-Utils编写测试文件

vue add @vue/unit-jest

第二种

需要手动安装各种依赖并且自行配置

  1. 安装 Jest 和 Vue Test Utils
yarn add jest @vue/test-utils -D
  1. babel-jest 、 vue-jest 和 [email protected]
babel-jest vue-jest [email protected]
  • bebel-jest用于处理js文件
  • vue-jest用于处理vue文件
  • [email protected]是因为Jest不认识Babel7,需要安装该依赖防止报错
  1. 配置文件,在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中配置

效果

image

生成覆盖率

修改命令即可

"scripts": {
    "test": "jest --coverage"
  }

效果
image

  • Stmts:语句覆盖率(statement coverage),表示是不是每个语句都执行了
  • Branch:分支覆盖率(branch coverage),表示是不是每个if代码块都执行了
  • Funcs:函数覆盖率(function coverage),表示是不是每个函数都调用了
  • Lines:行覆盖率(line coverage),表示是不是每一行都执行了

该命令执行后还会生成coverage文件夹,里面有一个index.html文件,打开可以通过网页查看覆盖率
image

假如要收集整个项目所有文件的测试覆盖率,那么可以通过配置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/**']
}

一些坑

报错1
image

这是因为我的项目引入了ant-design-vue这个第三方组件,Jestnode环境下运行时不认识这些第三方组件,需要我们注册组件,这里不推荐使用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标签的使用

需求

我们需要在不同屏幕宽度情况下显示不同的图片,这时候我们就需要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指定多张不同分辨率的图片

Canvas 和 SVG 的区别

SVG

特点

  • 表示可缩放矢量图形
  • 基于 XML,意味着 SVG DOM 中的每个元素都是可用的
  • 可以为某个元素附加 Javascript 事件
  • 每个被绘制的图形均视为对象。对象的属性发生变化,浏览器会重新渲染

优缺点

  • 不依赖分辨率
  • 支持事件处理器
  • 最适合带有大型渲染区域的应用程序(比如谷歌地图)
  • 复杂度高会减慢渲染速度(任何过度使用 DOM 的应用都不快)
  • 不适合游戏应用

Webpack之清空打包清空dist文件夹

需求

每次打包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()
  ]
}

对HTML语义化的理解

概念

  • 根据内容的结构化,选择合适的标签
  • 通俗的讲就是用正确的标签做正确的事情

DOCTYPE 的作用

作用

  • 是一种文档类型声明
  • 告诉浏览器使用什么渲染模式
  • 省略默认进入怪异模式

package.json中bin字段的作用

常用于编写命令行工具

"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

利用$attrs和$listeners来封装第三方组件

需求

在封装第三方组件时,经常会遇到的问题是要通过封装的组件去使用第三方组件自身的属性和事件

例子

我们封装了一个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>

要注意的是,我们这里要设置inheritAttrsfalse时,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>

如何在 VSCode 中更愉快地使用 JavaScript

如何在 VSCode 中更愉快地使用 JavaScript

智能提示

JSDoc

JSDoc可以让我们通过代码注释,让 VSCode 为我们自己的代码提供提示,只需要在函数上方输入/**能补全函数相关的注释,比如传参类型,返回值类型等,其实就是块注释,更多用法参考文档

微信截图_20211121105557

typings/d.ts

当我们使用npm install下载了第三方模块后,一般情况下使用时会有智能提示,这是什么原理呢?

image

原来像lodash这样的第三方模块在发布到 npm 库上时一般也会发布一个d.ts文件(按住 ctrl 点击或者按 F12 该模块的函数可以跳转对应的d.ts文件位置),这个文件为模块里的函数和对象提供了类型建议

image

  1. 首先检查该模块本身是否包含d.ts文件,如果有,直接使用
  2. 然后检查项目文件夹是否包含d.ts文件,如果有,直接使用,因为我们可以自行编写d.ts文件
  3. 检查社区是否为这个模块编写了d.ts文件,也就是模块是否带有对应的@types/前缀的模块,如果有,VSCode 会自行下载使用,不需要我们手动下载

jsconfig.json

我们可以在这个配置文件中手动设置需要提示的模块,即使该模块没有下载到本地

{
  "typeAcquisition": {
    "include": ["jquery"]
  }
}

image

ts-check

ts-check可以让我们为某个js文件启动类型检查,需要在第一行添加@ts-check注释,如果没有遵守类型,VSCode可以提示错误
image

前端自动化测试的介绍

自动化测试的好处

  • 提前发现bug,及时修复
  • 修改代码保证原有逻辑不受影响

种类

  • 单元测试:用来检测项目当中的最小可测单元,例如工具函数、基础组件等
  • 集成测试:在单元测试的基础上,不同功能集成在一起,验证整体功能
  • UI测试:并不是只对ui设计效果的验证,而是只对数据渲染、交互上的验证
  • 端对端测试:相对真实的模拟真实操作验证

vue和react的组件测试本质也属于单元测试或者集成测试

工具

  • 单元测试:Jest、Mocha
  • UI测试:Test Render、Enzyme
  • 端到端:Cypress、Nightwatch、Puppeteer、TestCafe

npm init都干了什么

npm init用的最多的地方就是初始化一个package.json文件

当这段命令后加上<initializer>,也就是npm init <initializer>时,会在npm库上寻找名为create-<initializer>的npm包,并用npx #50 临时安装这个包,然后执行其package.jsonbin属性对应的脚本,会创建或更新package.json并运行一些与初始化相关的操作

命令 等同
npm init foo npx create-foo
npm init @usr/foo npx @usr/create-foo
npm init @usr npx @usr/create

npx是什么?

作用

  • 直接调用项目安装的模块,不需要配置script字段
  • 可以临时下载模块,使用后删除,避免全局安装模块
  • 执行GitHub源码

display 的属性值及作用

属性值 作用
none 元素不显示,并且从文档流中移除
block 默认宽度为父元素宽度,可设置宽高,换行显示
inline 默认宽度为内容宽度,不可设置宽高,同行显示
inline-block 默认宽度为内容宽度,可设置宽高,同行显示
list-item 与block相同,同时有列表标记
table 以块级表格显示
inherit 从父元素继承display属性

常用的 meta 标签有哪些?

作用

  • 不会显示在页面中,但浏览器可以解析
  • 告诉浏览器如何显示内容或重新加载页面
  • 给搜索引擎提供关键词搜索
  • 其他web服务

说一下 web worker

作用

  • 执行脚本过程中页面不可响应,直到脚本执行完成
  • web worker是运行在后台的脚本,独立于其他脚本,不会阻塞主线程,影响页面性能
  • 通过postMessage将复杂操作的结果返回给主线程

代码规范之Vue参数命名

name

组件名应该始终是多个单词,应该始终是PascalCase,避免跟现有的以及未来的HTML元素冲突,因为所有HTML元素名称都是单个单词

export default {
    name: 'ToDoList',
    .....
}

prop

  • 声明prop的时候,其命名应该始终使用camelCase,因为在JavaScript中更自然
  • 模板和JSX中应该始终使用kebab-case,在HTML中更自然
<MyComponent my-name="reiner">
export default {
  name: 'MyComponent',
  // ...
  props: {
    myName: {
       type: String,
       required: true,
    }
  }
}

router

Vue Router Path命名采用kebab-case,用snake或者camelCase会被当成一个单词,搜索引擎无法区分语义

{
  path: '/user-info',
  name: 'UserInfo',
  component: UserInfo
}

模板中组件

  • 在单文件组件和字符串模板中组件名应该总是PascalCase
  • 在DOM模板中应该总是kebab-case
<!-- 在单文件组件和字符串模板中 -->
<MyComponent/>

<!-- 在DOM模板中 -->
<my-component></my-component>

自闭合组件

  • 在单文件组件、字符串模板和JSX中没有内容的组件应该自闭合
  • 在DOM模板永远不要自闭合
<!-- 在单文件组件和字符串模板中 -->
<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+动词的形式

事件方法

  • 命名方法:camelCase
  • 命名规范: handle+名称(可选)+ 动词
<template>
  <div
    @click.native.stop="handleItemClick()"
    @mouseenter.native.stop="handleItemHover()">
  </div>
</template>

<script>

export default {
  methods: {
    handleItemClick () {
      //...
    },
    handleItemHover () {
      //...
    }
  }
}
</script>

代码规范之项目文件规范

常用命名规范

  • camleCase(小驼峰式命令法——首字母小写)
  • PascalCase(大驼峰式命令法——首字母大写)
  • kebab-case(短横线连接式)
  • snake(下划线连接式)

项目名

全部采用小写方式,已短横线分隔,例my-project-name

目录名

有复数结构时,要采用复数命名法,例docsassets

图像文件名

全部采用小写方式,优先选择单个单词命名,多个单词命名以下划线分隔,例banner_sina.gif

HTML文件名

全部采用小写方式,优先选择单个单词命名,多个单词命名以下划线分隔,例error_report.html

CSS文件名

全部采用小写方式,优先选择单个单词命名,多个单词命名以短横线分隔,例date-picker.scss

JavaScript文件名

全部采用小写方式,优先选择单个单词命名,多个单词命名以短横线分隔,例index.jsaccount-modle.js

快速记忆方法:静态文件下划线,编译文件短横线

head 标签有什么作用,其中什么标签必不可少?

作用

  • 定义文档的头部,是所有头部元素的容器
  • 引用资源:脚本、样式表等
  • 描述文档:元信息、文档的标题、在 Web 中的位置、和其他文档的关系等
  • 一般包含的数据不作为内容显示给用户

渐进增强和优雅降级之间的区别

渐进增强

  • 主要是针对低版本的浏览器进行页面重构
  • 保证基本的功能情况下,再针对高级浏览器进行效果、交互等方面的改进和追加功能,提升用户体验。

利用v-bind使组件的属性更具有可读性

需求

我们常常要将一个对象的属性都作为prop传入组件中,但这样会导致可读性降低,这时我们可以使用v-bind一次性传入

优化

params: {
  id: 1,
  name: 'vue'
}

优化前

<MyComponent :id="params.id" :name="params.name" />

优化后

<MyComponent v-bind="params" />

Webpack之引入图片

引入图片的三种方式

  1. html中的img标签
  2. css的背景图片
  3. js动态引入

打包html中引入的图片

  1. 安装依赖
yarn add html-loader url-loader file-loader -D
  1. 配置
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,引入的图片的看不了

  1. index.html中引入图片
<img src="./avator.jpg" />
  1. 效果
    image

js中引入

  1. 入口文件处引入
import imgSrc from "./avator.jpg";
const img = document.getElementsByTagName("img")[0];
img.src = imgSrc;
  1. 配置
    其实就是在html引入图片配置的基础减少html-loader的配置

css中引入

  1. 引入
.box {
  display: flex;
  width: 100px;
  height: 100px;
  background-color: #000;
  background-image: url(./avator.jpg);
}
  1. 配置
    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(),
  ],
};

使用Testing Library对vue进行单元测试

安装依赖

假设你已经使用vue-cli创建了一个vue项目但没有勾选单元测试的相关配置,那么可以跟着我安装需要工具依赖

yarn add @vue/cli-plugin-unit-jest @testing-library/vue @testing-library/jest-dom -D
  • @vue/cli-plugin-unit-jest:vue-cli的插件,底层就是Jest测试框架用于运行测试和预设配置
  • @testing-library/vue:提供vue相关的测试API,比如加载组件什么的,底层也是vue test utils
  • @testing-library/jest-dom:由于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-libraryjest

执行命令

yarn test

Jest会自动找到目录的测试文件并运行
image

一些坑

报错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 的作用

img 中 srcset 的作用

作用

  • 在响应式页面中根据不同屏幕大小显示不同的图片
  • 比如手机下就没必要加载大尺寸图片,可以选择加载小图片,不仅可以使页面更快看到内容,还可以节省流量
  • 有时大尺寸的图片在小尺寸屏幕下不美观,需要准备多种尺寸的图片

使用

<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,因为电脑屏幕宽度远超与 128px256px,也就是触发了sizes默认的媒体查询,也就是128px,此时浏览器能够给予img元素的最大宽度为128px,此时浏览器会优先选择小于或者等于128w对应的图片
image

接下来我们切换浏览器到响应式模拟手机设备,可以看到如果我们在128px下看到的是256px.jpg这张图片,你可能会好奇等于或者小于128px不是应该加载128px.jpg吗,这是因为设备像素比的存在,一般在手机设备下,手机上的1px等于电脑上的2px,这里就不拓展了,总而言之,我们要模拟的屏幕宽度基础乘以 2,也就是256px,属于等于或者小于256w的范围,也就加载了256px.jpg这张图片
image

同理,如果我们将屏幕宽度调到比128px大,比256px小的情况下,会选择加载512px.jpg这张图片
image

这里有个注意点,当我们在电脑上模拟时,浏览器有一个缓存机制就是一旦选择加载了大分辨率图片则不管你怎么调整屏幕大小,浏览器都不会重新切换成小分辨率图片,当然正常情况在手机上不可能像这样随意调整屏幕大小,只会加载首次加载时最适合当前屏幕的图片,所以不用担心这个问题
image

拓展

  • srcset还有根据屏幕分辨率加载不同分辨率的图片,不过好像现在用的比较少,有兴趣的可以去了解一下
  • 还一个问题就是不同屏幕尺寸页面的美观问题,利用到picture元素和source元素,下篇文章讲解

代码规范之Vue组件命名

单文件组件名

文件拓展名为.vue单文件组件,命名应该始终是单词大写(PsascalCase)

components/
|- MyComponent.vue

单例组件名

  • 专门为应用定制
  • 每个页面只使用一次
  • 不接受任何prop
  • 例如头部和侧边栏组件每个页面都会使用

The前缀命名

components/
| - TheHeading.vue
| - TheSiderbar.vue

基础组件名

  • 不包含业务
  • 在不同页面中大量使用
  • API抽象,通过不同配置实现不同功能

Base前缀命名

components/
| - BaseButton.vue
| - BaseTable.vue

业务组件

  • 可复用
  • 只在当前项目中使用
  • 包含一些业务
  • 拥用自身dataprop

Custom前缀命名

components/
| - CustomCard.vue

紧密耦合的组件名

和父组件紧密耦合的子组件应该以父组件作为前缀命名。因为编辑器通常会按字母顺序组件文件,所以这样做可以把相关联的文件排在一起

components/
| - TodoList.vue
| - TodoListItem.vue
| - TodoListItemButton.vue

组件名中单词顺序

如下面用于搜索和设置功能的组件

components/
| - SearchButtonClear.vue
| - SearchButtonRun.vue
| - SearchInputQuery.vue
| - SearchInputExcludeGlob.vue
| - SettingsCheckboxTerms.vue
| - SettingsCheckboxLaunchOnStartup.vue

完整单词的组件名

能不用缩写就不要缩写

Webpack之CSS单独文件导出

需求

随着项目的增大,我们不想把那么多的样式都放在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"
+    })
+  ]
}
  • MiniCssExtractPlugin可以配置输出文件名
  • [name]为占位符,引入的时候是什么名字,导出的时候就是什么名字
  • css/表示导出到css文件夹下

效果

image

Webpack之打包CSS

Webpack之打包CSS

需求

我们知道webpack默认只能打包JS文件和JSON文件,打包以外文件需要相应的loader支持

JS中引入CSS

  • index.css
.box {
  width: 100px;
  height: 100px;
  background-color: #000;
}
  • index.js
import "./index.css";
console.log("hello webpack");

安装css-loader

yarn add css-loader -D

配置css-loader

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文件中
image
注意:此时创建一个html文件,引入打包出来的bundle文件,打开页面是看不到任何效果的,因为css代码还在js代码中,我们需要style-loader将我们的css代码放进style标签中

安装style-loader

yarn add style-loader -D

配置style-loader

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的顺序,否则可能报错

效果

image

Vue2与Vue3的区别

双向绑定

双向绑定实现原理由Object.defineProperty改为Proxy

Object.defineProperty的缺点

  • 深度监听需要一次性递归
  • 无法监听新增属性/删除属性(需要Vue.set Vue.delete辅助)
  • 无法原生监听数组,需要特殊处理

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解决的问题

  • 可以监听到对象深层属性的获取,设置或者删除等操作,也就是说可以不用一开始一次性递归处理所有深层属性变成响应式,可以什么时候获取,什么时候设置响应式
  • 能监听新增/删除的属性
  • 能原生监听数组

Fragment

Vue2中规定一个vue组件只能有一个根节点,而Vue3中多个节点会被包裹在Fragment元素中,该元素不会在DOM数中被渲染

emits

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

单个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)">
  `
})

Composition API

Vue2采用的是Options API编写方式,如下:

export default {
  props: {},
  data() {
    return {};
  },
  watch: {},
  computed: {},
  methods: {},
};

Options API的缺点

  • 随着组件复杂度的增加,代码越来越长,处理单个功能的相关代码被分散到各处,我们必须不断跳转查找相关代码,使阅读和理解造成困难,我们需要将相关代码整个到一起
  • 提取不同组件都需要的共用代码,我们虽然可以使用mixins,但那也造成命名冲突,来源不清晰的问题

Composition API的用法
官方文档写的挺清楚的

生命周期钩子

  • beforeCreatecreated改成setup
  • 其他在原来的基础上加上on前缀

开始学webpack之前必须知道的一些概念

开始学webpack之前必须知道的一些概念

Webpack诞生之前

  • 早期的项目需要将一个个JavaScript文件通过script标签引入到页面,一个文件相当于一个模块,并且还要按顺序引入,不然容易导致变量丢失等问题
  • 随着Node.js的出现和发展,借助Node.js可以对文件操作的能力,诞生了如gulpgrunt等可以为我们打包js的打包工具

Webpack是什么

  • 借着上面提到的历史我们可以得出,Webpack最初诞生的目的就是作为我们打包js的工具
  • 但同时随着如各种loaderplugin热更新等概念的出现,使webpack的功能不再仅仅是打包js那么简单

loader

  • webpack本身只能打包js和json格式的文件,但实际项目中我们还有cssscsspngts等其他文件,这时我们就需要使用loader来让它正确打包
  • loader就是处理编译js和json以外的文件时用的

plugin

webpack打包构建的过程中,有时我们需要plugin在这个过程中的某个时机做些特殊处理来改变最终打包的结果

postcss

  • 专门用于转换css的工具,比如转换后提供更好的兼容性等
  • postcss本身只是作为一个平台,真正发挥转换作用的是这个平台上的各种插件

babel

  • 专门用于转换JavaScript语法的工具,比如转换后提供更好的兼容性
  • babel本身只是作为一个平台,真正发挥转换作用的是这个平台上的各种插件或者说预设

@babel/core

babel的核心库,所有的核心api都在这个库里,这些api可供babel-loader调用

@babel/preset-env

插件的集合,包含所有es6转化为es5的规则

@babel/polyfill

@babel/preset-env只是提供了语法转换的规则,但是它并不能弥补浏览器缺失的一些新的功能,如一些内置的方法和对象,如Promise,Array.from等,此时就需要polyfill来做js的垫片,弥补低版本浏览器缺失的这些新功能

core-js

JavaScript标准库的polyfill,而且它可以实现按需加载。使用@babel/preset-env的时候可以配置core-js的版本和core-js的引入方式 @babel/polyfill依赖core-js

browserslist

  • 声明了一段浏览器的合集,我们的工具可以根据这个合集描述,针对性的输出兼容性代码,browserslist应用于babelpostcss等工具当中
  • browserslist可以在package.json文件配置,也可以单出写一个.browserslistrc文件进行配置
  • 工具会自动查找.browserslistrc中的配置,如果没有发现.browserslistrc文件,则会去package.json中查找

chunk

代码块(一个js模块)

chunks

多个chunk的组合

Webpack之实现一个plugin

编写一个类

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文件
  • 这里一定要写apply方法,webpack会通过apply方法启动插件
  • PluginName可以写成普通function,apply必须挂载到原型对象上
  • class类中的apply不能写成箭头函数
  • webpack的compiler钩子,查看钩子决定你的插件要在哪一步做什么

配置

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(),
  ],
};

效果

image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.