1 babel
这篇文章主要收录了babel工作原理,webpack中的loader、plugin、devServer、resolve、打包,Source Map,Vite,Element ui等等相关知识
1.1 babel
babel是一个工具链,依赖各种插件对es6+ 的语法转化为低版本(浏览器可识别)的语法
当然,如果一个个插件都要安装,那就太麻烦了,这时会用到预设
preset
预设可以将常用的插件集成到一起
可以安装 @babel/preset-env 使用预设
1.2 babel-loader
webpack是模块化打包工具,并不会帮我们将es6的代码转化为es5,这个转化工作由babel-loader(依赖babel)完成,当然,还需要使用相关的插件~(比如转化const、let的插件,转化箭头函数的插件等等)。当然,可以使用预设
1.3 babel的配置文件
可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写:
- babel.config.json(或.js、.cjs、.mjs)文件,推荐
- .babelrc.json(或babelrc,.js ,.cjs,.mjs)文件
比如 babel.config.js
module.exports = {
presets: [
'@babel/preset-env'
]
}
1.4 底层原理
你可能想问:babel如何将(es6、ts、react)转换成es5的呢?
其实,将源代码(原生语言)转化成另一种源代码(目标语言),这是编译器的职责
babel就类似于一个编译器
工作流程
babel也拥有编译器的工作流程:
- 解析(Parsing)
- 转化(Transformation)
- 生成(Code Generation)
可以去 github.com/jamiebuilds… 查看详细过程
原生代码 -> 词法分析 -> 数组 -> 语法分析 -> AST -> 遍历 -> 访问 -> 应用插件 -> 新的AST -> 目标代码
node.js中通过babel体验es6模块化
babel语法转换插件,可以把高级的、有兼容性的js代码转换成低级的、没有兼容性的代码
- npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/node
- npm install --save @babel/polyfill
- 项目根目录创建文件babel.config.js
- babel.config.js 文件内容如下
const presets = [
["@babel/env", {
targets: {
edge: "17",
firefox: "60",
chrome: "67",
safari: "11.1"
}
}]
];
module.exports = { presets };
5.通过 npx babel-node index.js 执行代码(高版本npm自带npx)
2 webpack
2.1 当前web开发面临的困境
- 文件依赖关系错综复杂
- 静态资源请求效率低
- 模块化支持不友好
- 浏览器对高级javascript特性兼容程度较低
2.2 webpack概述
webpack是一个流行的前端项目构建工具(打包工具),可以解决当前web开发中所面临的的困境。
webpack提供了友好的模块化支持,以及代码压缩混淆、处理js兼容性问题、性能优化等强大功能,从而让程序员把工作的重心放到具体的功能实现上,提高开发效率和项目的可维护性。
grunt/gulp和webpack有什么不同?
grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
而webpack更加强调模块化开发管理,而文件压缩合并,预处理等功能,是他附带的的功能。
2.3 webpack的基本使用
安装webpack首先要安装node.js,node.js自带了软件包管理工具npm
在项目中安装和配置webpack
- 运行
npm install webpack webpack-cli -D命令,安装webpack相关的包 - 在根目录中,创建名为 webpack.config.js 的 webpack配置文件
- 在webpack 的配置文件中,初始化如下基本配置:
module.exports = {
mode: 'development'//mode 用来指定构建模式还有 production
}
4.在package.json 配置文件中的scripts 节点下,新增dev 脚本如下:
"scripts": {
"serve": "webpack"//scripts节点下的脚本,可以通过npm run 执行
}
5.在终端中运行 npm run serve 命令,启动webpack 进行项目打包。
development模式下的main.js(还未压缩)
production模式下的main.js
开发时使用development模式,提高编译速度,
发布时使用production模式。
配置打包的出口与入口
webpack的4.x版本中默认约定:
- 打包的入口文件为 src -> index.js
- 打包的输出文件为 dist -> main.js
如果要修改打包入口与出口,可以在 webpack.config.js 中新增配置信息:
const path = require('path')//导入node.js中专门操作路径的模块
module.exports = {
entry: path.join(__dirname, './src/index.js'),//打包入口文件的路径
output: {
path: path.join(__dirname,'./dist'),//输出文件的存放路径
filename: 'bundle.js'//输出文件名称
}
}
2.4 webpack中的loader
通过loader打包非js模块
实际开发中,webpack默认只能打包处理以.js后缀名结尾的模块,其它非.js后缀名结尾的模块,webpack默认处理不了,需要调用loader加载器才可以正常打包,否则会报错!
loader加载器可以协助webpack打包处理特定的文件模块,比如:
- less-loader 可以打包处理 .less相关的文件
- sass-loader 可以打包处理 .sass相关的文件
- url-loader 可以打包处理 css 中与 url路径相关的文件
loader的调用过程
webpack中加载器的基本使用
打包处理css文件
css-loader只负责加载
还需要style-loader将样式添加到DOM中
style-loader
- 运行
npm i style-loader css-loader -D命令,安装处理css文件的loader - 在 webpack.config.js 的module -> rules 数组中,添加loader规则如下:
-
// 所有第三方文件模块的匹配规则 module: { rules: [ { test: /.css$/, use: [ 'style-loader', 'css-loader' ] } ] }
其中,test表示匹配的文件类型(正则表达式),use表示对应要调用的loader
注意:
- use 数组中指定的loader顺序是固定的
- 多个loader的调用顺序是:从后往前调用
打包处理less文件
- 运行
npm i less-loader less -D命令,安装处理less文件的loader - 在 webpack.config.js 的module -> rules 数组中,添加loader规则如下:
-
// 所有第三方文件模块的匹配规则 module: { rules: [ { test: /.less$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] } ] }
打包处理scss文件
- 运行
npm i sass-loader node-sass -D命令,安装处理sass文件的loader - 在 webpack.config.js 的module -> rules 数组中,添加loader规则如下:
-
// 所有第三方文件模块的匹配规则 module: { rules: [ { test: /.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ] } ] }
配置postCSS自动添加css的兼容前缀
- 运行
npm i postcss-loader autoprefixer -D命令 - 在项目根目录中创建postcss的配置文件postcss.config.js,并初始化如下配置:
-
const autoprefixer = require('autoprefixer')//导入自动添加前缀的插件 module.exports = { plugins: [ autoprefixer ]//挂载插件 } - 在 webpack.config.js 的module -> rules 数组中,修改css的loader规则如下:
-
// 所有第三方文件模块的匹配规则 module: { rules: [ { test: /.css$/, use: [ 'style-loader', 'css-loader', 'postcss-loader' ] } ] }
打包样式表中的图片和字体文件
- 运行
npm i url-loader file-loader -D命令 - 在 webpack.config.js 的module -> rules 数组中,添加loader规则如下:
-
// 所有第三方文件模块的匹配规则 module: { rules: [ { test: /.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/, use: [ { loader: 'url-loader', options: { limit: 90 * 1024 } } ] } ] }
当加载的图片,小于limit时,会将图片编译成base64字符串形式。
当加载的图片,大于limit时,需要使用file-loader模块进行加载。
然而,还没结束。
去浏览器检查时,并没有显示图片,打开控制台发现图片路径错了
解决方法:在webpack.config.js里添加一个output的配置,使用共用路径
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: 'dist/'
}
还有一个问题:打包之后图片名字变了
解决方法:在webpack.config.js里的module里的file-loader添加一个option
options: {
limit: 90 * 1024,
name: 'img/[name].[hash:8].[ext]'
}
打包处理js文件中的高级语法
- 安装babel转换器相关的包:
npm install -D babel-loader @babel/core @babel/preset-env - 在webpack.config.js的module -> rules数组中,添加loader规则如下:
-
// exclude为排除项,表示babel-loader不需要处理node_modules中的js文件 { test: /.js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } }
资源模块类型
webpack5开始,我们就可以直接使用资源模块类型(asset module type),来替代某些loader
- asset/resource 发送一个单独的文件并导出URL,替代file-loader
- asset/inline 导出一个资源的data URI,替代url-loader
- asset/source 导出资源的源代码。之前替代raw-loader
打包处理vue文件
安装 npm install vue-loader vue-template-compiler -d相关的包
配置
{
test: /.vue$/,
use: ['vue-loader']
}
runtime-compiler和runtime-only区别(掌握)
runtime-compiler
可以解析template
template->ast->render->vdom->ui
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el: '#app',
template: '<App/>',
components: {
App
}
})
runtime-only(性能更高,代码量更少)
不解析template
render->vdom->ui
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
el: '#app',
render: h => h(App)
})
那么,.vue文件的template是由谁处理的呢?
vue-template-compiler,.vue文件的template已经被转换成render函数了
render函数的完整写法
h只是代号
render: function (createElement) {
// 1.普通用法createElement('标签',{标签的属性},['标签内容'])
return createElement('h2',{class: 'box'},['hello'])
// 2.也可以传入组件对象createElement(App)
}
vue不同版本的含义
| vue(.runtime).global.(.prod).js | vue(.runtime).esm-browser.(.prod).js | vue(.runtime).esm-bundler.js | vue.cjs.(.prod).js |
|---|---|---|---|
| 通过使用 | 用于原生ES模块导入使用 | 用于webpack、rollup、parcel等构建工具 | 服务器端渲染使用 |
| 会暴露一个全局的Vue来使用 | 通过使用 | 构建工具默认的是vue.runtime.esm-bundler.js | 通过require()在node中使用 |
| 如果需要解析template模板,需要手动指定vue.esm-bundler.js |
vue中编写DOM元素
vue开发过程中有三种方式来编写DOM元素:
- template,通过源码中一部分代码对其进行编译
- render函数(h),直接返回一个虚拟节点
- .vue文件的template,通过vue-loader对其进行编译和处理
vue程序运行过程
解析.vue文件
安装 npm install vue-loader@next -D (vue-loader默认是处理vue2)
同时还需要安装 npm install @vue/compiler-sfc -D (以前是@vue/vue-template-compiler)
同时还需要一个插件, 引进来。const { VueLoaderPlugin } = require('vue-loader/dist/index'),并通过new 调用
2.5 webpack中的plugin
为打包的文件添加版权信息
插件名:BannerPlugin,webpack自带
webpack.config.js+
const webpack = require('webpack')
plugins: [
new webpack.BannerPlugin('最终版权归翟思丰所有')
]
打包的HTML的plugin
真实发布项目时,发布的是dist文件夹的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也就没有意义
所以,我们需要将index.html文件打包到dist文件夹中,这个时候可以使用HtmlWebpackPlugin插件。
安装:npm i -d html-webpack-plugin (非webpack自带)
注意,使用这个插件需要删除之前在output中添加的publicPath属性,否则插入的script中的src可能会有问题
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
template: 'index.html'
})
]
html-webpack-plugin做了什么?
- 自动生成一个index.html文件(可以指定模板来生成)(这里指定index.html模板)
- 将打包的js文件,自动通过script标签插入到body中
js压缩的plugin
在项目发布之前,我们需要对js等文件进行压缩处理
插件:uglifyjs-webpack-plugin
安装 npm i -d uglifyjs-webpack-plugin
配置:
const uglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
plugins: [
new uglifyjsWebpackPlugin()
]
2.6 devSever
为了完成自动编译,webpack提供了几种方式:
- webpack watch mode
- webpack-dev-sever(常用)
- webpack-dev-middleware
webpack watch mode
在该模式下,只要一个文件发生更新,那代码将被重新编译
如何开启watch呢?
方式一,在导出配置中,添加watch:true
方式二,在启动webpack的命令中,添加 --watch 参数
webpack-dev-sever
npm install webpack-dev-server -D命令,安装支持项目自动打包的工具- 修改 package.json -> scripts 中的dev命令如下:
-
"scripts": { "serve": "webpack serve"//script节点下的脚本,可以通过npm run 执行 } - 运行
npm run serve命令,重新进行打包 - 在浏览器中访问 http://localhost:8080(可变) 地址,查看自动打包效果
注意:
webpack-dev-server帮我们打包成功的文件,并没有以文件的形式输出,而是将bundle文件保存到内存中了,(一般的打包都是输出成文件,然后再放到内存中),这样可以提高开发效率。它使用了一个叫memfs的库
contentBase
devServer: {
contentBase: './public'
}
当在打包后的资源里找不到相关资源时,会去contentBase指定的路径里找
hot
模块热替换(Hot Module Replacement)HMR
是指应用程序运行过程中,替换、添加、删除模块,而无需刷新整个页面
为什么需要模块热替换?
当一个写了小修改,由于webpack-dev-server会自动帮我们编译并刷新页面,导致某些状态被修改掉了(期望保留这些状态),这不是我们期望的,(期望:替换、添加、删除模块时,无需刷新整个页面),而且只更新修改的模块,性能提高
webpack-dev-server已经默认开启
当然也可以自己配置
target: 'web',
devSever: {
hot: true
}
到这里还不没做到模块热替换
你还需要在main.js里加上这么一个逻辑
if(module.hot) {
module.hot.accpet(需要HMR的模块, () => {})
}
回调函数可以进行其它处理,可省。
当然,要是很多模块需要HMR,那这样写起来会非常麻烦。
真实开发中,vue-loader已经帮我们做了(react是react-refresh,React Hot Loader已弃用)
HMR的原理是什么呢?
webpack-dev-server会创建两个服务:提供静态资源的服务(express)和Socket服务(net.Socket)
Socket服务是长连接,什么是长链接?
在通信两端有通道之后,可以实时任意时刻通信(比如微信、直播)
那短连接是什么样的?
客户端发请求 --> 和服务器建立连接 --> 服务器响应 --> 断开连接
这样就是短连接
所以HMR的原理:
- 长链接有一个好处是建立连接后双方可以通信(服务器可以直接发送文件到客户端)
- 当服务器监听到对应的模块发生变化时,会生成两个文件: manifest.json和update chunk.js
- 通过长连接,服务器可以直接将这两个文件主动发送给客户端(浏览器)
- 浏览器拿到这两个新文件后,通过HMR runtime机制,加载这两个文件,并且针对修改的模块进行更新
host
设置主机地址
默认localhost
如果希望其它ip的主机也可以访问,可以设置0.0.0.0
localhost和0.0.0.0的区别
- localhost:本质上是一个域名,通常情况会被解析成127.0.0.1;
- 而127.0.0.1是一个回环地址(Loop Back Address) ,回环地址发出去的包,直接被自己接收;
- 正常的数据包是应用层 - 传输层 - 网络层 - 数据链路层;
- 而回环地址主机发出的包,是在网络层直接就被获取到了,不走数据链路层了。
- 这样,其它ip地址的主机就收不到回环地址主机发出的包了
- 比如,监听127.0.01时,在同一网段下的主机中,通过ip地址是不能访问的
- 而0.0.0.0监听IPV4上所有地址,在根据端口找到不同的应用程序,在同一网段下的主机中,通过ip地址是可以访问的(比如两台电脑连同一个wifi就可以访问项目啦)
devSever: {
host: 'localhost'
}
port
设置端口
devSever: {
host: 'localhost'
}
open
设置编译完成自动打开浏览器
devSever: {
open: true
}
compress
设置静态资源压缩成gzip格式(你放心,浏览器可以识别),大概可压缩60%(不压缩html)。
devSever: {
compress: true
}
proxy
使用代理处理跨域问题
proxy: {
'^/api': {
target: 'http://localhost:8888',
pathRewrite: {
'^/api': ''
},
changeOrigin: true
}
}
为什么要设置pathRewrite: { '^api': '' }?
因为请求中会出现多出/api,代理时将它重写为空
为什么要设置changeOrigin: true?
有些服务器会对请求头进行校验,虽然proxy进行了代理处理了跨域,但请求头里的源还是代理之前的源,而设置了该属性为true时,代理的同时将请求头的源改成代理之后的源
historyApiFallback
解决SPA页面在路由跳转之后,进行页面刷新时,返回404的错误
devSever: {
historyApiFallback: true
}
2.7 resolve
设置模块如何被解析
- 开发中会有各种模块依赖,这些模块可能是自己编写的代码,也可能来自第三方库
- resolve可以帮助webpack从每个require/import语句中,找到需要引入的合适模块代码
- webpack使用enhanced-resolve来解析文件路径
webpack能解析3种文件路径:
- 绝对路径,直接获取模块,不需要进一步解析
- 相对路径,使用import/require的资源文件所在目录,被认为是上下文目录,在import/require中给定的相对路径,会拼接上下文路径,来生成模块的绝对路径
- 模块路径,在resolve.modules中指定的所有目录检索模块(默认值是['node_modules']);可以通过设置别名的方式来替换初始模块路径(alias)
extensions
解析到文件时自动添加后缀名
默认值是 ['.wasm', '.mjs', '.js', '.json']
导入模块时,以上这4种后缀的文件就可以不写后缀啦,当然,你也可以添加其它后缀
resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json']
}
alias
路径起别名
当有些模块层级比较深时,写起来比较麻烦,此时就可以使用别名
resolve: {
alias: {
'@': resolve('src'),
'assets': resolve('@/assets')
'components': resolve('@/componenets'),
'views': resolve('@/view')
}
}
- import时用@
- src="url"时用~
2.8 开发和生产环境的配置分离
1.在根目录新建一个文件夹config,并在里面新建三个文件
- common.config.js(公共配置)
- dev.config.js(开发时配置)
- prod.config.js(发布时配置)
common.config.js
开发和生产都需要的配置
const path = require("path");
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpack = require('webpack')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const uglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
// publicPath: 'dist/'
},
module: {
rules: [
{ test: /.css$/, use: [ 'style-loader', 'css-loader' ] },
{
test: /.jpg|png|gif|bmp|ttf|eot|svg|woff|woff2$/,
use: [
{
loader: 'url-loader',
options: {
limit: 90 * 1024,
name: 'img/[name].[hash:8].[ext]'
}
}
]
},
// exclude为排除项,表示babel-loader不需要处理node_modules中的js文件
{
test: /.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /.vue$/,
use: ['vue-loader']
},
]
},
plugins: [
new CleanWebpackPlugin(),
new VueLoaderPlugin(),
new webpack.BannerPlugin('最终版权归翟思丰所有'),
new HtmlWebpackPlugin({
template: 'index.html'
}),
// new uglifyjsWebpackPlugin()
],
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
dev.config.js
module.exports = {
devServer: {
contentBase: './dist',
inline: true
}
}
prod.config.js
const uglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new uglifyjsWebpackPlugin()
]
}
合并
安装 webpack-merge插件
既然分开了,那就合并起来
npm i -d webpack-merge
在prod.config.js+
const uglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
const webpackMerge = require('webpack-merge')
const commonConfig = require('./common.config')
module.exports = webpackMerge(commonConfig, {
plugins: [
new uglifyjsWebpackPlugin()
]
})
在dev.config.js+
const webpackMerge = require('webpack-merge')
const commonConfig = require('./common.config')
module.exports = webpackMerge(commonConfig, {
devServer: {
contentBase: './dist',
inline: true
}
})
2.9 打包
分包
自己编写的代码逻辑会被统一打包到app_hash.js中,
而第三方依赖会被打包到chunk_hash.js中
当自己编写的代码逻辑越来越多,打包之后的app_hash.js会越来越大,
app_hash.js越大,首屏加载时间就越长~
webpack提供了分包策略,可以将想要打包的内容放进别的文件,而不是app_hash.js
使用import() ,它的返回值是个promise
通过import函数导入的模块,webpack打包的时候,会对其进行分包操作
企业级的项目打包发布
主要的发布流程:
- 生成打包报告,根据报告分析具体的优化方案
- tree-shaking
- 为第三方库启用cdn加载
- 配置组件的按需加载
- 自定义首页内容
3 Source Map
3.1 生产环境遇到的问题
前端项目在投入生产前,都需要对JavaScript源代码进行混淆压缩,从而减小文件的体积,提高文件的加载效率。此时就不可避免的产生了另一个问题:
对压缩混淆之后的代码除错(debug)是一件及其困难的事情
- 变量被替换成没有任何语义的名称
- 空行和注释被剔除
3.2 什么是Source Map
是一个信息文件,里面存储着位置信息。也就是说,Source Map文件存储着代码压缩混淆后的前后对应关系,
有了它,除错的时候,除错工具将直接显示原始代码,而不是转换后的代码,能够极大方便后期的调试
3.3 webpack开发环境下的Source Map
在开发环境下,webpack 默认启用了Source Map功能.当程序运行出错时,可以直接在控制台提示错误行的位置,并定位到具体的源代码
默认Source Map的问题
开发环境下默认生成source map,记录的是生成后的代码的位置。会导致运行时报错的行数与源代码的行数不一致的问题
解决默认source map的问题
开发环境下,在webpack.config.js中添加如下的配置
module.exports = {
mode: 'development',
devtool: 'eval-source-map'
}
3.4 source map的最佳实践
开发环境:
- 建议把devtool的值设置为eval-source-map
- 好处:可以精准定义到具体的错误行
生产环境:
- 建议关闭source map或将devtool的值设置为nosources-source-map
- 好处:防止源码泄露,安全
4 vue脚手架
4.1 Vue-CLI
用于快速生成vue项目基础架构,其官网为:cli.vuejs.org/zh/
CLI 是Command-Line interface,命令行界面,俗称脚手架
使用步骤
安装vue脚手架
npm install @vue/cli -g
如果要更新
npm update @vue/cli -g
基本用法
使用Vue CLI创建vue项目
// 1.基于 交互式命令行 的方式,创建 新版vue项目
vue create my-project
// 2.基于 图形化界面的方式,创建 新版vue项目
vue ui
项目名称不能包含中文
注意:
不推荐这种方式,因为package.json 主要用来管理包的配置信息;为了方便维护,推荐将vue脚手架相关的配置,单独定义到 vue.config.js 配置文件中
module.exports = {
configureWebpack: {
...
}
}
vue-cli3和2区别
- vue-cli3基于webpack 4打造,vue-cli2还是webpack3
- vue-cli3的设计原则是”0配置“,移除的配置文件根目录下的build和config等目录
- vue-cli3还提供vue ui命令,提供了可视化配置,更加人性化
- 移除了static文件夹,新增了public文件夹,并且index.html移动到public
Vue-CLI原理
- 执行
npm run serve; - 根据
serve脚本对应的命令(vue-cli-service),去 node_modules/bin下; - 找到与该命令同名的文件夹(vue-cli-service),并执行里面的代码;
- 不过vue-cli-service.js文件只是一个软连接,真正执行的代码不在这里;
- 在node_modules/@vue/cli-service下的package.json,指定了真正执行代码的位置;
-
"bin": { "vue-cli-service": "bin/vue-cli-service.js" } - node_modules/@vue/cli-service下有个bin目录,bin目录下有vue-cli-service.js;
- 具体在vue-cli-service.js下做了什么,暂时不讨论。。。;
讲了这么多
主要是为了证实Vue-CLI是依赖于webpack的
4.2 Vite
发音 /vit/ ,不是/vait/~
官方定位:下一代前端构建和开发工具
组成
- 一个开发服务器(基于原生ES模块提供了丰富的内置的功能,HMR速度非常快)
- 一套构建指令(它使用rollup打开代码,并且是预配置的,可以输出生产环境优化过的静态资源)
基本使用
在此之前,你是否想过这两个问题:现代浏览器不是基本支持es模块化了吗? ,我在开发阶段不使用构建工具,在打包阶段再使用构建工具可以吗?
第一个问题,你说的对。在script元素的属性里加上 type="module" ,浏览器就可以识别模块了(注意引入模块记得加后缀哦);
第二个问题,有这个想法很好。Vite的思想就类似于这个想法:开发阶段不使用构建工具,打包阶段再使用。
但是,开发阶段不需要构建工具真的好吗?
开发阶段我们不止使用es模块化,还有可能有 .ts文件、.vue文件、.less文件等等,这些文件目前浏览器是不支持的,需要转化成浏览器识别的文件。
不仅如此,如果不使用构建工具,包之间的依赖太多,就会发送过多的网络请求,比如lodash-es
而Vite,就可以解决这两个弊端。
安装
要求node版本大于12
来个局部的 npm install vite -D
使用
因为局部安装,使用npx运行 npx vite
然后你会发现很快的它就帮我们搭建了个本地服务,而且上面两个弊端也解决啦
特性
-
css,less不需要loader,也不需要进行相关的配置啦(但是你还是要安装less哦)
-
而postcss只需安装还有相关插件
npm install postcss postcss-preset-env -D,配置postcss.config.js即可// postcss.config.js module.exports = { plugins: { require('postcss-preset-env') } } -
直接支持ts,不需要相关配置
-
vue,只需要安装相关插件,并配置vite.config.js,并且安装 @vue/compiler-sfc 插件
vue3单文件组件 @vitejs/plugin-vue vue3 JSX @vitejs/plugin-vue-jsx vue2 underfin/vite-plugin-vue2 vite.config.js
const vue = require('@vitejs/plugin-vue') module.exports = { plugins: { vue() } }
Vite2原理
vite2是如何做到对less、ts等等的支持的呢?
- 它会开启一个本地服务器,使用了一个叫Connect的库(vite1用koa),将对ts、less文件的请求拦截并转发;
- 将ts、less等文件交给相关工具,转化为es6的对应的js;
- 相关工具返回那些js给本地服务器;
- 本地服务器再将那些js传给浏览器;
同时,执行vite的时候,第一次会进行预打包,类似于缓存,下次再执行vite时就快很多
还有,vite也依赖ESBuild:
- 构建速度快,不需要缓存;
- 支持ES6和CommonJS的模块化;
- 支持ES6的Tree Shaking;
- 支持Go、js的API;
- 支持ts、jsx等语法编译;
- 支持Source Map;
- 支持代码压缩;
- 支持扩展其它插件;
为什么ESBuild这么快呢?
- 使用Go语言编写,直接将ast转化成机器代码,无需经过字节码;
- 充分利用CPU多核,尽可能让他们饱和运行;
- 源码从0开始编写,并且不使用第三方库,一开始就考虑了各种性能问题
快,不是没有理由的~
打包
npx vite build
预览
npx vite preview
当然这些命令可以自定义成脚本的形式~
vite的脚手架
当然,真实开发我们也不会从0开始搭建,而是使用vite的脚手架
安装
来个全局
npm install @vitejs/create-app -g
使用
create-app 项目名
5 Element-UI的基本使用
一套为开发者、设计师和产品经理准备的基于vue2.0的桌面端组件库。
官网地址为:element-cn.eleme.io/#/zh-cn
5.1 基于命令行方式手动安装
- 安装依赖包
npm i element-ui -s - main.js导入element-ui相关资源
// 导入组件库
import ElementUI from 'element-ui';
// 导入组件相关样式
import 'element-ui/lib/theme-chalk/index.css'
// 配置Vue插件
Vue.use(ElementUI);
5.2 基于图形化的界面自动安装
- 运行
vue ui命令,打开图形化界面 - 通过 vue 项目管理器,进入具体的项目配置面板
- 点击 插件->添加插件,进入插件查询面板
- 搜索
vue-cli-plugin-element并安装 - 配置插件,实现按需导入,从而减少打包后项目的体积