Babel 是一个 JavaScript 编译器,用于将高版本的JavaScript代码转为向后兼容的JS代码,ES6+ => ES5/ES3。同时也可转换 JSX 语法为 JavaScript。
可单独使用 babel 或者通过下面三种方式:
babel 本身不具有任何转化功能,它把转化的功能都分解到一个个 plugin 里面。因此当我们不配置任何插件时,经过 babel 的代码和输入是相同的。
Babel插件
babel 的转译过程分为三个阶段,这三步具体是:
babel-traverse
对其进行遍历,在此过程中进行添加、更新及移除等操作;babel-generator
。单独使用babel来完成整个工作流时,通过 @babel/cli
在终端(命令行)中快速使用 babel 命令进行代码转换。
// Babel 的核心功能包含在 `@babel/core` 模块中
npm install @babel/core @babel/cli @babel/preset-env -D
// 通过babel命令,解析src下的所有js文件,并转换到lib文件夹中
./node_modules/.bin/babel src --out-dir lib --presets=@babel/env
npx babel src --out-dir lib --presets=@babel/env
// --out-dir 可缩写为 -o
上面的 @babel/preset-env
结合 @babel/core
预设进行代码转换。命令 preset 还可添加详细参数进行控制,其他命令同样如此,为避免命令行过长,可利用配置文件 babel.config.json:
{
"presets": [
[
"@babel/preset-env",
{
// targets 简易写到.browserslistrc文件中,不推荐配置在这里
"targets": "last 2 Chrome versions",
// 在预设中配置include后,转换时总是会启用include的插件
"include": ["@babel/plugin-transform-arrow-functions"],
// 决定是否引入polyfill,false(不引入)、usage(按需引入)和entry(项目入口处引入)
"useBuiltIns": usage,
// core-js 版本,可以选择2(默认)或者3,只有当useBuiltIns 不为 false 时才会生效
"corejs": 3
}
]
],
"plugins": [
[
// 用于转换箭头函数的插件
"@babel/plugin-transform-arrow-functions",
{
"spec": true
}
]
]
}
Babel提供了一百来个插件,并提供预设(presets),预先设置好的一系列插件包。一些常用的预设有:
虽然 @babel/preset-env
可以转换大多高版本的JS语法,但是一些ES6原型链上的函数(比如数组实例上的的filter、fill、find等函数)以及新增的内置对象(比如Promise、Proxy等对象),是低版本浏览器本身内核就不支持。需要通过 @babel/polyfill
,加入兼容代码。但是打包出来生成的文件非常的大,且污染全局变量,polyfill 给很多类的原型链上添加函数,因此推荐引入core-js
与 regenerator-runtime
两个包来替代。
在 webpack 中使用 babel 简单例子如下:
module.exports = {
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ["@babel/preset-env"]
}
}
]
}
]
}
}
更过配置见官网。
webpack 细则见官网,是一个模块化打包工具,通过loader转换文件,plugin注入钩子,最后输出由多个模块合成的文件,如图所示。
它主要是分析项目结构,找到js模块以及浏览器不能直接运行的拓展语言(TS,less等),并将其打包成合适的格式供浏览器使用。webpack 专注于模块化项目,开箱即用,具有如下特性:
Webpack 与 grunt、gulp 的区别
与 webpack 类似的工具还有 rollup、parcel 等。webpack适用于大型复杂的前端站点构建,rollup适用于基础库的打包,如vue、react,parcel适用于简单的实验性项目,他可以满足低门槛的快速看到效果。
webpack 具有四个核心的概念,分别是 Entry(入口)、Output(输出)、loader 和 Plugins(插件)。
开发中通常将基础配置文件拆分为base,client,server等,搭建一个简单的Vue脚手架例子如下(基于 webpack4.x):
vue-loader.config.js
module.exports = (isDev) => {
return {
preserveWhitepace: true,
extractCSS: !isDev,
cssModules: {
localIdentName: isDev ? '[path]-[name]-[hash:base64:5]' : '[hash:base64:5]',
camelCase: true
},
// hotReload: false, // 根据环境变量生成
}
}
webpack.config.base.js:搭建基础配置
const path = require("path");
const createVueLoaderOptions = require("./vue-loader.config");
const isDev = process.env.NODE_ENV === "development";
const config = {
mode: process.env.NODE_ENV || "production", // development || production
target: "web",
entry: path.join(__dirname, "../client/index.js"),
output: {
filename: "bundle.[hash:8].js",
path: path.join(__dirname, "../dist"),
},
module: {
rules: [
{
test: /\.(vue|js|jsx)$/,
loader: "eslint-loader",
exclude: /node_modules/,
enforce: "pre",
},
{
test: /\.vue$/,
loader: "vue-loader",
options: createVueLoaderOptions(isDev),
},
{
test: /\.jsx$/,
loader: "babel-loader",
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: /node_modules/,
},
{
test: /\.(gif|jpg|jpeg|png|svg)$/,
use: [
{
loader: "url-loader",
options: {
limit: 1024,
name: "resources/[path][name].[hash:8].[ext]",
},
},
],
},
],
},
};
module.exports = config;
webpack.config.client.js:搭建客户端配置
const path = require("path");
const HTMLPlugin = require("html-webpack-plugin");
const webpack = require("webpack");
const merge = require("webpack-merge");
const ExtractPlugin = require("extract-text-webpack-plugin");
const baseConfig = require("./webpack.config.base");
const isDev = process.env.NODE_ENV === "development";
const defaultPluins = [
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: isDev ? '"development"' : '"production"',
},
}),
new HTMLPlugin(),
];
const devServer = {
port: 8000,
host: "0.0.0.0",
overlay: {
errors: true,
},
hot: true,
};
let config;
if (isDev) {
config = merge(baseConfig, {
devtool: "#cheap-module-eval-source-map",
module: {
rules: [
{
test: /\.styl/,
use: [
"vue-style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
sourceMap: true,
},
},
"stylus-loader",
],
},
],
},
devServer,
plugins: defaultPluins.concat([
new webpack.HotModuleReplacementPlugin(),
// new webpack.NoEmitOnErrorsPlugin()
]),
});
} else {
config = merge(baseConfig, {
entry: {
app: path.join(__dirname, "../client/index.js"),
// vendor: ['vue']
},
output: {
filename: "[name].[chunkhash:8].js",
},
module: {
rules: [
{
test: /\.styl/,
use: ExtractPlugin.extract({
fallback: "vue-style-loader",
use: [
"css-loader",
{
loader: "postcss-loader",
options: {
sourceMap: true,
},
},
"stylus-loader",
],
}),
},
],
},
optimization: {
splitChunks: {
chunks: "all",
},
runtimeChunk: true,
},
plugins: defaultPluins.concat([
new ExtractPlugin("styles.[contentHash:8].css"),
// new webpack.optimize.CommonsChunkPlugin({
// name: 'vendor'
// }),
// new webpack.optimize.CommonsChunkPlugin({
// name: 'runtime'
// })
]),
});
}
module.exports = config;
构建流程
通过上面例子,总结webpack的构建流程如下:
提高webpack的构建速度
CommonsChunkPlugin
来提取公共代码externals
配置来提取常用库DllPlugin
和DllReferencePlugin
预编译资源模块 通过DllPlugin来对那些我们引用但是绝对不会修改的npm包来进行预编译,再通过DllReferencePlugin 将预编译的模块加载进来Happypack
、thread-loader
实现多线程加速编译webpack-uglify-parallel
来提升 uglifyPlugin 的压缩速度。 原理上webpack-uglify-parallel采用了多核并行压缩来提升压缩速度Tree-shaking
和 Scope Hoisting
来剔除多余代码webpack的热更新原理
热更新HMR,可以在不刷新浏览器的情况下,将新变更的模块替换掉旧的模块。就是webpack和浏览器之间维护一个websocket,当本地资源发生变化的时候,webpack会向浏览器推送更新,并带上构建时的hash,让浏览器与上一次的资源进行比对。
lodar与plugin
关于bundle,chunk 和 module
文件指纹
文件指纹是指打包后输出文件的名的后缀。
关于 source map
source map 是将编译、打包、压缩后的代码映射回源代码的过程。打包压缩后的代码不具备良好的可读性,想要调试源码就需要 source map。map 文件只要不打开开发者工具,浏览器是不会加载的。显示环境一般有三种处理方案:
hidden-source-map
:借助第三方错误监控平台 Sentry 使用。nosource-source-map
:只会显示具体行数以及查看源代码的错误栈。安全性比 source-map 高。source-map
:通过 nginx 设置将.map文件指对白名单开发。注意:在生产环境中避免使用 inline- 和 eval-,因为它们会增加 bundle 体积大小,并降低整体性能。
webpack-dev-server和http服务器如nginx的区别
如何利用webpack来优化前端性能?
UglifyJsPlugin
和 ParallelUglifyPlugin
来压缩JS文件, 利用 optimize-css-assets-webpack-plugin
来压缩css关于 Tree-shaking
Tree-shaking 是指在打包中去除那些引入了,但是在代码中没有被用到的那些死代码。在webpack中Tree-shaking是通过 uglifyJsPlugin
来Tree-shaking JS,CSS 需要使用 Purify-CSS
。
我们常用 webpack 来配置单页应用,多页应用配置可参考 https://zhuanlan.zhihu.com/p/117656993。所谓单页应用(SPA),就是整个应用只有一个主页面,其余的“页面”,实际上是一个个的“组件”。单页应用中的“页面跳转”,实际上是组件的切换,在这个过程中,只会更新局部资源,页面不会整个刷新。也正是因为这个原因,当我们的前端代码有更改,重新部署之后,如果用户不主动刷新,就会发现有“资源缓存”。单页应用明显的弊端就是不利于 SEO。
生成公/私密钥
ssh-keygen -t rsa -C "[email protected]"
gitignore失效问题
git ignore只会对不在git仓库中的文件进行忽略,如果这些文件已经在git仓库中,则不会忽略。所以如果需要忽略的文件已经提交到本地仓库,则需要从本地仓库中删除掉,如果已经提交到远端仓库,则需要从远端仓库中删除。删除.gitignore文件才能实际生效。.gitignore 文件只能作用于 Untracked Files
,也就是那些从来没有被 Git 记录过的文件(自添加以后,从未 add 及 commit 过的文件)。
想要删除已经提交的文件,使用:
git rm -r --cached xxx.js
git commit -m " commit ....."
git push
git rm --cached
删除的是追踪状态,而不是物理文件。
常用git命令
目前可知的主要环境细分如下:
git config --global user.name "你的名字或昵称"
git config --global user.email "你的邮箱"
git config --global credential.helper store
此时会在本地保存一个文本文档,用于记录账户与密码,以便以后不用每次操作命令都输入密码。
git init
执行完在本文件夹下生成 .git 文件夹,生成文件树。
git add .
git commit -m 'description'
# 法1
git remote add origin https://git.coding.net/username/projectname.git
# 法2 申请Github token,通过token的方式避免重复输入用户名密码,git clone 的时候同样带上token
git remote set-url origin https://[email protected]/YourName/xxx.git/
git pull origin master
git push origin master
git branch [branch name]
git checkout [branch name]
# 或直接创建并切换
git checkout -b [branch name]
git add .
git commit -m "msg"
git push origin [branch name]
但是有时某个分支的命名与远程仓库中的分支冲突时我们需要将本地仓库中的分支删除掉,以下是删除本地分支与远程分支的基本步骤:
在push的过程中必须保持本地与远程分支的名称一致性,否则会报错。
cherry-pick
目的:把某个分支中的其中部分 commit merge 到 master 中。步骤如下:
如果出现冲突,则先解决冲突,再 git add
(将解决了冲突的文件添加到暂存区),然后 git cherry-pick --continue
。
merge 合并分支
git merge feature
下面内容来自 https://juejin.cn/post/6872020320333594637
git fetch&git pull
pull 后回滚到之前版本
git reflog master # (查看本地master分支历史变动纪录)
git reset --hard <COMMIT_ID> #(恢复到之前位置)
# git reset --hard master@{1}
git clone
# -b 指定分支
git clone -b [chekout name] https://[email protected]/Name/xxx.git/
软件从零开始到最终交付,大概包括以下几个阶段:规划、编码、构建、测试、发布、部署和维护。
瀑布式开发
瀑布式开发的基本流程是 需求 → 设计 → 开发 → 测试 , 是一个更倾向于严格控制的管理模式 。
敏捷开发
敏捷开发是一种以用户需求进化为核心、迭代、循序渐进的开发方法。首先把 用户(客户 )最关注的软件原型做出来,交付或上线,在实际场景中去 快速 修改弥补需求中的不足,再次发布版本。通过一些敏捷实践方式,细化story ,提供更小的迭代。如此循环,直到用户(客户)满意。适用于需求不明确、创新性或者需要抢占市场的项目。
DevOps
DevOps 强调通过一系列手段来实现既快又稳的工作流程,使每个想法(比如一个新的软件功能,一个功能增强请求或者一个 bug 修复)在从开发到生产环境部署的整个流程中,都能不断地为用户带来价值。这种方式需要开发团队和运维团队密切交流、高效协作并且彼此体谅。此外,DevOps 还要能够方便扩展,灵活部署。有了 DevOps,需求最迫切的工作就能通过自助服务和自动化得到解决;通常在标准开发环境编写代码的开发人员也可与 IT 运维人员紧密合作,加速软件的构建、测试和发布,同时保障开发成果的稳定可靠。
DevOps 即开发运维一体化。DevOps平台搭建工具如下(例子):
参考 https://q.shanyue.tech/deploy/,https://www.zhihu.com/question/58702398/answer/1755254160