Webpack-Babel

2022-04-28  本文已影响0人  Imkata

为什么需要babel?

事实上,在开发中我们很少直接去接触babel,但是babel对于前端开发来说,目前是不可缺少的一部分。开发中,我们想要使用ES6+的语法,想要使用TypeScript,开发React项目,它们都是离不开Babel的。所以,学习Babel对于我们理解代码从编写到线上的转变过程至关重要。

那么,Babel到底是什么呢?
Babel是一个工具链,主要用于旧浏览器或者环境中将ECMAScript 2015+代码转换为向后兼容版本的JavaScript,包括:语法转换、源代码转换等。

Babel命令行使用

babel和postcss一样,是一个独立的工具,不和webpack等构建工具一块也可以单独使用。

如果我们希望在命令行中尝试使用babel,需要安装如下库:

npm install @babel/cli @babel/core -D

首先我们写如下ES6的代码:

const message = "Hello World"; //ES6的const
const names = ["abc", "cba", "nba"];
names.forEach(item => console.log(item));//ES6的箭头函数

然后使用babel来处理我们的源代码:

npx babel src --out-dir dist

执行上面的命令后发现,依然还是ES6的箭头函数语法,这是因为我们没安装必要的插件。

插件的使用

比如我们需要转换箭头函数,那么我们就可以使用箭头函数转换相关的插件。

先安装:

npm install @babel/plugin-transform-arrow-functions -D

命令行使用:

npx babel src --out-dir dist --plugins=@babel/plugin-transform-arrow-functions

查看转换后的结果,我们会发现 const 并没有转成 var,这是因为 plugin-transform-arrow-functions并没有提供这样的功能,我们需要使用 plugin-transform-block-scoping 来完成这样的功能。

先安装:

npm install @babel/plugin-transform-block-scoping -D

命令行使用:

npx babel src --out-dir dist --plugins=@babel/plugin-transform-block-scoping
,@babel/plugin-transform-arrow-functions

转换后的ES5代码如下:

"use strict";

var message = "Hello World";
var names = ["abc", "cba", "nba"];
names.forEach(function (item) {
  return console.log(item);
});

Babel的预设preset

但是如果要转换的内容过多,一个个设置插件是比较麻烦的,我们可以使用预设(preset),预设就是把我们常用的插件都集合到一起了。

安装@babel/preset-env预设:

npm install @babel/preset-env -D

执行如下命令也会全部转换成功。

npx babel src --out-dir dist --presets=@babel/preset-env

Babel的底层原理

Babel是如何做到将我们的一段代码(ES6、TypeScript、React)转成另外一段代码(ES5)的呢?
从一种源代码(原生语言)转换成另一种源代码(目标语言),这是什么的工作呢?就是编译器,事实上我们可以将babel看成就是一个编译器。Babel编译器的作用就是将我们的源代码,转换成浏览器可以直接识别的另外一段源代码。

Babel也拥有编译器的工作流程:

https://github.com/jamiebuilds/the-super-tiny-compiler

Babel编译器执行原理

Babel的执行阶段:

当然,这只是一个简化版的编译器工具流程,在每个阶段又会有自己具体的工作:

babel-loader

在实际开发中,我们通常会在构建工具中通过配置babel-loader 来对其进行使用,比如在webpack中。我们需要去安装相关的依赖,如果之前已经安装了@babel/core,那么这里不需要再次安装。

npm install babel-loader @babel/core

我们可以设置一个规则,在加载js文件时,使用我们的babel-loader :

我们必须指定使用的插件才会生效:

babel-preset

如果我们一个个去安装使用插件,那么需要手动来管理大量的babel插件,我们可以直接给webpack提供一个preset,webpack会根据我们的预设来加载对应的插件列表,并且将其传递给babel。

比如常见的预设有三个:

安装preset-env:

npm install @babel/preset-env

Babel的配置文件

像之前postcss.config.js一样,我们可以将babel的配置信息放到一个独立的文件中,babel给我们提供了两种配置文件的编写。

它们两个有什么区别呢?
目前很多的项目都采用了多包管理的方式(babel本身、element-plus、umi等);

单独配置好之后,webpack.config.js里面的rules我们就写的更简单了,如下:

// {
//   test: /\.js$/,
//   use: {
//     loader: "babel-loader",
//     options: {
//       // plugins: [
//       //   "@babel/plugin-transform-arrow-functions",
//       //   "@babel/plugin-transform-block-scoping",
//       // ]
//       presets: [
//         "@babel/preset-env"
//       ]
//     }
//   }
// }
{
  test: /\.js$/,
  loader: "babel-loader"
}

Vue源码的打包

前面我们讲了,安装和使用Vue有四种方式:

方式一:在页面中通过CDN的方式来引入
方式二:下载Vue的JavaScript文件,并且自己手动引入
方式三:通过npm包管理工具安装使用它(webpack再讲)
方式四:直接通过Vue CLI创建项目,并且使用它

前两种方式我们讲过了,现在讲第三种方式,先安装vue:

//如果当前默认版本是vue3,直接安装就可以
npm install vue
//如果当前默认版本是vue2,需要加@next,也就是下一个版本的意思
npm install vue@next 
//不需要加-D,因为无论是开发还是上线我们都需要,默认是-S,运行依赖

和前两种方式不一样,现在vue就相当于一个模块,所以我们通过:
import { createApp } from 'vue';引入,代码中的vue就相当于一个模块。

在index.html里面编写模板:

<template id="my-app">
  <h2>我是Vue渲染出来的</h2>
  <h2>{{title}}</h2>
</template>

在main.js里面编写Vue相关的代码,指定模板。

界面上是没有效果的,并且我们查看运行的控制台,会发现如下的警告信息:

为什么报这个警告?

因为vue有两个版本:runtime+complier和runtime-only,默认我们上面导入的就是runtime-only,runtime-only是无法对template进行解析的。因为上面我们用到了template,所以只能使用runtime+complier版本的vue。

其实不止上面两个版本,打开node_modules/vue/dist,可以发现有很多版本:

下面讲一下不同版本的区别:

Vue打包后不同版本解析

上面的(.runtime)代表的是runtime-only的版本,如果不需要对template进行编译,就可以使用vue.runtime.global.js版本。(.prod)代表是否用生产版本,生产版本的代码是压缩的。

所以,上面的警告,我们指定版本后:

import { createApp } from 'vue/dist/vue.esm-bundler';

这样就没警告了,并且template也能正常被解析。

runtime+complier VS runtime-only

在Vue的开发过程中我们有三种方式来编写DOM元素:
方式一:template模板的方式(之前经常使用的方式);
方式二:通过.vue文件中的template来编写模板;
方式三:render函数的方式,使用h函数来编写渲染的内容;

它们的模板分别是如何处理的呢?

所以,Vue在让我们选择版本的时候分为:runtime+complier和runtime-only

VSCode对SFC文件的支持

上面的代码,模板是在index.html里面,在main.js里面指定模板和编写模板相关的数据和逻辑,这样它们就分开了,很麻烦。我们理想的是模板、数据、逻辑、样式都在一个文件里面,其他地方使用的时候就直接导入就好了,这就需要使用SFC单文件组件了。真实开发中多数情况下我们都是使用SFC( single-file components (单文件组件) )。

默认情况下,VSCode对.vue文件是没有代码高亮的,我们需要安装如下插件:

编写App.vue代码

接下来我们编写自己的App.vue代码:

下面就可以在main.js里面直接使用了:

App.vue的打包过程

我们对代码打包会报错,因为我们需要合适的Loader来处理.vue文件

这个时候我们需要使用vue-loader,默认情况下vue-loader是用来处理vue2的代码的,我们写的是vue3代码,所以加个@next。

npm install vue-loader@next -D

在webpack的模板规则中进行配置:

@vue/compiler-sfc

打包依然会报错,这是因为我们必须添加@vue/compiler-sfc来对template进行解析:

npm install @vue/compiler-sfc -D

另外我们需要配置对应的Vue插件,在webpack.config.js里面引入插件:

然后在下面进行使用:

重新打包即可支持App.vue的写法。

另外,我们也可以通过编写其他的.vue文件来编写自己的组件,然后在我们的APP.vue里面局部注册之后就可以使用了:

<template>
  <h2>我是Vue渲染出来的</h2>
  <h2>{{title}}</h2>
  <!-- 3. 使用组件 -->
  <hello-world></hello-world>
</template>

<script>
  // 1. 引入组件
  import HelloWorld from './HelloWorld.vue';

  export default {
    //2. 注册局部组件
    components: {
      HelloWorld
    },
    data() {
      return {
        title: "Hello World",
        message: "哈哈哈"
      }
    },
    methods: {

    }
  }
</script>

<style scoped>
  h2 {
    color: red;
  }
</style>

全局标识的配置

我们会发现控制台还有另外的一个警告:

在GitHub上的文档中我们可以找到说明:

这是两个特性的标识:

配置的地方就是我们配置BASE_URL的地方:

new DefinePlugin({
  BASE_URL: "'./'",
  __VUE_OPTIONS_API__: true,
  __VUE_PROD_DEVTOOLS__: false
}),

配置完后重新打包就没警告了。

因为我们现在是使用SFC单文件组件了,.vue文件里面的template会被vue-loader解析(内部使用@vue/compiler-sfc来解析),那么我们导入的时候就不需要导入vue.esm-bundler.js了,直接导入vue即可,因为webpack,rollup 和 parcel 等构建工具,构建工具中默认是使用vue.runtime.esm-bundler.js。

// import { createApp } from 'vue/dist/vue.esm-bundler';
import { createApp } from 'vue';
上一篇 下一篇

猜你喜欢

热点阅读