码猴之家

原谅我放荡不羁爱coding


  • 首页

  • 分类

  • 归档

  • 标签

bable兼容性解决方案

发表于 2020-03-22 |

babel兼容js解决方案

为什么需要babel?

在日趋月异的前端的发展中,前端工程化模块化的加快,w3c新的标准和api对于前端来说越来越方便,而对于这些新的语法糖和新的标准,在头疼的前端浏览器面前造成的不能统一兼容的问题也凸显出来,为了能够将这些新的特性和一些语法糖进行兼容处理,babel就应运而生

原理

如何将这些不兼容的代码进行装换,整个过程分为解析,转译的过程,首先我们需要了解@babel/core这个包,这个包是bable的一个核心基础包,该包的作用就是将我们的不兼容的代码进行装换成我们的ast,通过我们的presets(类似于plugins的合集)和plugins进行转义成符合兼容性要求的代码(ps:babel只是转译新标准引入的语法,比如ES6的箭头函数转译成ES5的函数;而新标准引入的新的原生对象,部分原生对象新增的原型方法,新增的API等(如Proxy、Set等),这些babel是不会转译的。需要用户自行引入polyfill来解决)

plugins

plugins的作用就是来讲babel转义的ast进行plugin的类别再进行一次转义,常见的plguins的名字中基本为@babel/plugin-transform-xxx, 比如@babel/plugin-transform-class等

presets

在项目中需要使用的大量的需要转义的写法事,太多的plugins显得比较繁琐,所以preset就出现了,我认为他就是一个plugins的集合。@babel/preset-env是为了解决早期,preset标准不统一,存在es20xx的各个版本不统一的问题.

polyfill

polyfill作为es6的一个shim,主要的原理就是对于将core.js和regenerator runtime包装了下,这两个包才是真正的实现代码所在。使用babel-polyfill会把ES2015+环境整体引入到你的代码环境中,让你的代码可以直接使用新标准所引入的新原生对象,新API等,一般来说单独的应用和页面都可以这样使用
使用方法的话一般分为两种,主要是:

1
2
3
4
1. 入口文件进行直接引入
require('@babel/polyfill')
2. webpack打包入口entry中添加
entry:['@babel/polyfill', 'xxx.js']

runtime

在编译后,我们会发现,很多兼容的api和方法会被编译成兼用的方法。这样就导致了一个问题,在每个文件里都会重复这样的方法和方式,这就导致了代码的臃肿性,所以我们在这里提到了runtime

1
2
3
4
5
6
{
presets:['@bable/preset-env'],
plugins:[
"@babel/plugin-transform-runtime"
]
}

@babel/runtime 的作用就是将那些兼容后的模块进行统一处理,即进行模块化的应用,而@babel/plugin-transform-runtime这个插件的作用就是用来自动化引用runtime里面的模块。

1
2
3
4
5
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

微前端最佳实践

发表于 2020-03-01 |

#微前端最佳实践

微前端最佳实践

发表于 2020-03-01 |

#微前端最佳实践

通过node 中rpc通讯的的buffer来认识ascii码,unicode, 以及utf8编码方式

发表于 2018-01-22 | 分类于 buffer |

通过node 中rpc通讯的的buffer来认识ascii码,unicode, 以及utf8编码方式

###rpc
在前端的业务逻辑里主要是客户端和服务端的通讯,主要通过ajax,websocket等方式,而在服务端直接的通讯一般我们认定为rpc通讯

buffer

在rpc通讯的过程中所需要的数据必须是二进制的,buffer其实就是一个二进制的数据流载体,用来存放二进制数据, buffer能够将二进制数据以不同的编码方式进行存储,比如 ascii, utf-8, base64等主流方式,默认是使用utf-8的方式

1
const buffer = new Buffer.form(xxxx, type)

那么utf-8又是什么他们跟unicode 和 ascii码又有什么联系

ascii码

我们到知道,计算机的最原始的编码方式就是 01 这种二进制的方式进行编程的,在使用折中二进制编码方式来表示我们的需要展现的内容文字,每个字节需要8个这样的二进制组成的,由于计算机这种技术是国外发明的,2的8次方也就是256 完全能够将24个字母全部概括了,这就是ascii码的概念

问题来,在计算机发展后,全球不同于语言,如何才能让计算机也能够完全真确的识别更多的字符呢,ascii这种方式就远远不能够实现了,于是unicode就被提出来了

unicode

unicode像是一个大词典,每个unicode字符都对应一个二进制,比如说”帅“的unicode是\u5e05,对应的二进制是101111000000101, 长度是15, 也就是说这个帅子至少需要2个字节组成,但是我们不是很清楚通过两个字节改如何识别,是两个独立的字节表示两个字符,还是两个字节表示一个字符,所以我们需要一个用来规范的编码方式,进行约定识别,这时utf-8 和 utf-16等编码方式就应运而生。

utf-8

就拿utf-8来举例子,这也是我们最常用的一个编码方式,该编码方式是如何进行允运作的呢,我们来看下

1
2
3
4
5
6
7
编码规则如下:
Unicode 十六进制码点范围 UTF-8 二进制
0000 0000 - 0000 007F 0xxxxxxx
0000 0080 - 0000 07FF 110xxxxx 10xxxxxx
0000 0800 - 0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000 - 0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

根据上面的规则表我们不难发现,从低到高表示unicode需要几个字符能够表示,而且在通过utf-8编码过后,会形成一个比较规则的格式,为几个字符,头字节头部固定就会有几个1以及一个0, 而后续字符都是以10为开头,让后我们将16进制unicode码转化成2进制从右往左插入到对应的空缺,不足已0填充,就是最后能够通过utf-8识别的 二进制码, 这样通过头字符就知道是后续几个字节表示的是一个字符还是两个。上面刷子是在第三层也即是三个字符组成,填补完为 11100101 10111000 10000101

webpack3中常用的一些操作

发表于 2016-12-22 | 分类于 webpack |

#webpack3中常用的一些操作

##新建配置文件
开始之前我们需要新建一些我们开始需要的文件,package.json文件, index.js入口文件,首先我

1
2
$ mkdir webpackdemo && yarn init && yarn webpack --dev
$ cd webacpkdemo && mkdir src && cd src && touch index.js

通过上面的命令行创建项目目录,并初始化配置文件,导入webpack, 并创建项目入口文件

在index.js中添加我们的内容,在这里我们引入lodash来作为本次的demo演示数据内容部分

1
$ yarn add lodash --dev

安装lodash后,进入index.js页面进行首次页面的操作

1
2
3
4
5
6
7
import _ from 'lodash'
function component(){
var element= document.createElement('div');
element.innerHtml = _.join(['你好','世界'],'');
return element
}
document.body.appendChild(component())

好我们的首次入口文件就已经添加好了,下面创建编译后的文件夹以及编译后的插入页面

1
$ mkdir dist && cd dist && touch index.html
1
2
3
4
5
6
7
8
9
10
11
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script src="bundle.js"></script>// bundle.js就是后面我们编译后的文件名
</body>
</html>

下面我们就行新webpack.config.js的编写,这个名字是webpack执行默认文件的名字,在执行webpack操作时会自动运行该文件。
在编写该文件之前我们尝试用最初的方法执行下编译

1
$ ./node_modules/.bin/webpack src/index.js dist/bundle.js

执行index.js并将生成bundle.js文件放入dist文件夹,这是最低级的办法,在工作中基本不会用到,下面则进行配置进行打包

1
2
3
4
5
6
7
8
const path = require('path')
module.epxort = {
entry:'./src/index.js',//入口文件
output:{
filename:'bundle.js',//编译后的文件名
path:path.resolve(__dirname, 'dist')//文件路径
}
}

在 package 文件中进行webpack的操作

1
2
3
"script":{
"build": "webpack"
}

运行命令行$ yarn run build,就会发现也会也会实现上面相同的功能

##打包其他类型文件
这部分内容,主要利用的是label的运用,在module模块下面的rules中添加我们需要打包的类型以及处理操作

####打包css文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const path = require('path')
module.epxort = {
entry:'./src/index.js',//入口文件
output:{
filename:'bundle.js',//编译后的文件名
path:path.resolve(__dirname, 'dist')//文件路径
},
module:{
rules:[
{
test:'\.css',//不要打包类型的匹配
use:[
'style-loader',
'css-loader'
]
//
}
]
}
}

这里注意,在webpack2 中-loader可省略的设置被取消掉了,必须要填写完全才可以运行,否则会报错,而执行操作的loader的相关功能,可以参展webpack官网进行配置

1
$ yarn add style-loader css-loader --dev

最后新建样式文件,并引入到index.js的文案里面

1
$ touch style.css
1
2
3
4
//style.css
.classname {
color:blue
}
1
2
3
4
5
6
7
8
9
import _ from 'lodash';
import './style.css';
function component(){
var element= document.createElement('div');
element.innerHtml = _.join(['你好','世界'],'');
element.classList.add('classname') //添加类名
return element
}
document.body.appendChild(component())

同上执行命令行运行就会发现生成两个文件,一个是js,一个是样式文件

###打包图片

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const path = require('path');
module.epxort = {
entry:'./src/index.js',//入口文件
output:{
filename:'bundle.js',//编译后的文件名
path:path.resolve(__dirname, 'dist')//文件路径
},
module:{
rules:[
{
test:/\.css/,//打包类型的匹配
use:[
'style-css',
'css-loader'
]
//
},
{
test:/\.(png|svg|jpg|gif)$/, //匹配图片
user:['file-loader']
}
]
}
}

同样在选择一张图片,并引入到入口文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
import _ from 'lodash';
import './style.css';
improt imgUrl from './img.png';
function component(){
var element= document.createElement('div');
var Img = new Image();
Img.src=imgUrl
element.innerHtml = _.join(['你好','世界'],'');
element.classList.add('classname') //添加类名
element.appendChild(Img)
return element
}
document.body.appendChild(component())
1
$ yarn add file-loader --dev

运行webpack 就会生成三中不同类型的文件,图片,样式,js文件。

###其他类型的打包
上面介绍了基础的一些文件的打包,其实还有可以打包的,比如说字体等,一些很多loader的配置,在这里就不一一举例了,可以自己全看文档进行学习

##输出管理

###多入口的添加
在一些时候我们需要进行多个入口文件,所以导致在编译的时候需要进行多入口的编译打包

1
2
3
4
5
6
7
8
9
10
11
12
const path = require('path');
module.epxort = {
entry:{
app:'./src/index.js',
other:'./src/other.js'
},//入口文件
output:{
filename:'[name].bundle.js',//编译后的文件名
path:path.resolve(__dirname, 'dist')//文件路径
},
...
}

通过上面的操作就会进行多入口的操作,下面filename中的[name],就表示entry中入口文件的key,打包编译后就会生成app.bundle.js和other.bundle.js两个文件,同时我们在index.html中添加引入other.bundle.js的入口,当时文件一多这样就太麻烦了,所以我梦需要插件的协助,也是plugins等。

###Plugins
插件的使用和目的都是为了大大减轻我们在操作中的痛点,能够自动化的完成我们需要手动完成的事情

html-webpack-plugin

html-webpack-plugin插件的作用就是将编译好的文件自动插入到html文件中,并且可以设置一些属性操作

1
$ yarn add html-webpack-plugin --dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const HtmlWebpackPlugin = require('html-webpack-plugin')
...
{
...
'plugins':[
new HtmlWebpackPlugin({
title:'demo', //设置html文件title
filename:'index.html', //写入html文件的文字,默认index
template:'./src/index.html', //设置模板文件,即文件内容会跟模板一样
inject:'body' //编译文件添加到html中的位置,true和body都会放到body的底部
})
]
...
}

执行webpack命令行,自动生成文件并且插入到模板文件中.

clean-webpack-plugin

我们每执行一次文件发现都会新增一次文件,这就导致我们必须要手动每次删除文件夹,clean-webpack-plugin插件很好的结局了这个问题

1
$ yarn add clean-webpack-plugin --dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const HtmlWebpackPlugin = require('clean-webpack-plugin')
...
{
...
'plugins':[
new HtmlWebpackPlugin({
title:'demo', //设置html文件title
filename:'index.html', //写入html文件的文字,默认index
template:'./src/index.html', //设置模板文件,即文件内容会跟模板一样
inject:'body' //编译文件添加到html中的位置,true和body都会放到body的底部
}),
new cleanWebpackPlugin(['dist']) //参数一位需要清理的目录
]
...
}

其实还有好多非常好用的插件,参展文档你可以慢慢学习各种差点的使用环境和方法

##开发环境
良好的开发环境能够大大增进开发的效率,事半工倍,在这介绍几个开发环境下常用到的配置项

devtool

在编译后的代码运行后,我们发现,开发工具里报错直接显示的是编译后的文件报错,这样的话导致我们很难定位到问题所在,加大了我们解决错误的时间和精力,所以我们添加devtool配置项能够定位到编译前文件的错误所在

1
2
3
4
5
...
{
devtool:'inline-source-map'// devtool的选项有很多,先选择报错最仔细的
}
...

这样子的话如果报错,问题很快找出位置并解决掉。

webpack-dev-server
故名思意,开发环境下设置的服务器,在开发过程中想要实时跟新自己的代码,查案效果的话,每次都需要编译是在太麻烦,webpack-dev-server就很好的解决了我们的痛点

1
$ yarn add webpack-dev-server --dev
1
2
3
4
5
...
devServer:{//监测代码是否改变,是则更新代码刷新页面
contentBase: path.resolve(__dirname, 'dist')//检测所在目录
}
...
1
2
3
4
// webpack.config.json
...
start : 'webpack-dev-server --open'; //--open打开浏览器,并开启node服务器,默认地址为localhost:8080
...

修改样式,保存,发现页面会自动刷新,但是在页面太多情况下,还是会造成刷新太慢太耗性能的问题,所以我们采用热加载的功能

模块热加载(HMR, Hot Module Replacement)

该功能很好的识别改动的模块,并只更新该模块的内容,效率大大提高同时,采用的是无刷新的更新方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
const webpack = require('webpack')
{
...
devserver:{
contentBase:path.resolve(__dirname, 'dist'),
hot:true, //设置启用HMR
hotOnly:true //报错不刷新页面
}
plugins:[
...,
new webpack.HotModuleReplacementPlugin(),//配合上面hot的设置才能生效
new webpack.NamedModulesPlugin()//打印时返回模块实际路径
]
...
}

>

webpack-dev-server 会为每个入口文件创建一个客户端脚本,这个脚本会监控该入口文件的依赖模块的更新,如果该入口文件编写了 HMR 处理函数,它就能接收依赖模块的更新,反之,更新会向上冒泡,直到客户端脚本仍没有处理函数的话,webpack-dev-server 会重新加载整个页面。如果入口文件本身发生了更新,因为向上会冒泡到客户端脚本,并且不存在 HMR 处理函数,所以会导致页面重载。

我们已经开启了 HMR 的功能,HMR 的接口已经暴露在 module.hot属性之下,我们只需要调用 HMR API即可实现热加载。当“被加载模块”发生改变时,依赖该模块的模块便能检测到改变并接收改变之后的模块。

下面我们在index页面进行module.hot的检测是否可以访问

1
2
3
4
5
6
7
//index.js文件地不添加
...
if(module.hot){
module.hot.accept('./print.js',function(){
console.log('更新更新!');
})
}

下面我们开启服务,发现修改样式等操作过后页面直接实现了热更新的功能

##生产环境
生产环境和开发环境的需求就不一样,基本上要求生成的文件体积小,没有多余的代码,那么我们怎么区别生产环境和开发环境呢。

设置变量进行辨别

1
$ webpack-p

这个命令行其实是一个缩写命令相当于 webpack–optimize-minimize–define process.env.NODE_ENV=”‘production’。

  1. 使用 UglifyJsPlugin,对代码进行压缩
  2. 运行 LoaderOptionsPlugin 插件,这个插件是用来迁移的,兼容处理
  3. 设置Node.js的变量,为后面做判断提供条件

在这个过程中为了能够在编译之前就能够识别这个环境变量,所以我们处理

1
$ yarn add cross-env --dev
1
2
3
4
5
6
//package.json
{
...
build:"cross-env NODE_ENV=production webpack -p"
...
}

下面我们在webpack.config.js文件中进行判断

1
2
3
4
5
6
7
8
9
10
11
12
const path = require('path');
module.epxort = {
entry:{
app:'./src/index.js',
other:'./src/other.js'
},//入口文件
output:{
filename:process.env.NODE_ENV=='production'?'[name].[chunkhash].js':[name].bundle.js,//编译后的文件名
path:path.resolve(__dirname, 'dist')//文件路径
},
...
}

注意,在这里设置chunkhash时,我盟们不能使用HMR,否则在编译时会导致报错,这就导致了我们在开启开发环境和生产环境时导致要手动屏蔽一些代码,这样很麻烦,所以我盟可以编写连个环境的配置代码,将一些公用的放在一个文件进行公用,这里就用到了webpack-merge

webpack-merge

我们先新建三个文件,webpack.common.js用来设置在开发和生产环境中公用的配置项,webpack.pro.js配置生产环境配置项,webpack.dev.js则配置生产环境的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
output: {
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
title: 'webpack demo',
filename: 'index.html'
}),
new CleanWebpackPlugin(['dist'])
],
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader','css-loader']
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//webpack.dev.js
cosnt path = require('path');
const Merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const webpack = require('webpack');
module.export = Merge(commonConfig,{
devtool:'cheap-module-eval-source-map',
devserver:{
contentBase:path.resolve(__dirname, 'dist'),
hot:true,
hotOnly:true
},
output: {
filename: '[name].bundle.js'
},
plugin:[
new webpack.defaultPlugin({
'process.env.NODE_NV':JSON.stringify('development') //设置node环境变量
})
new webpack.HotModuleReplacementPlugin()
new webpack.nameModulesPlugin()
]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//webpack.pro.js
cosnt path = require('path');
const Merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const webpack = require('webpack');
module.export = Merge(commonConfig,{
devtool:'cheap-module-source-map',
output: {
filename: '[name].[chunkhash].js'
},
plugin:[
new webpack.defaultPlugin({
'process.env.NODE_NV':JSON.stringify('development') //设置node环境变量
})
new webpack.optimize.UglifyJsPlugin()//压缩代码
]
})
1
2
3
4
5
6
7
8
9
10
//package.json
{
...
'script':{
...
'build:dev': webpack-dev-server --open --config webpack.dev.js,
'build:pro': webpack-dev-server --open --config webpack.pro.js
}
...
}

大功告成,这样子我们的两个简单的环境就算是配置完成了,需要更多的配置则可以查看官网倆选择性添加,添加配置的宗旨一定要牢记,是项目中需要什么东西我们才添加,而不是为了添加配置而配置。

牛逼

发表于 2014-12-22 | 分类于 webpack |

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Joker Chen

Joker Chen

少时不努力,老大做IT

6 日志
2 分类
7 标签
© 2016 - 2020 Joker Chen
由 Hexo 强力驱动
主题 - NexT.Pisces