浏览器支持ES6的最优解决方案

ES6系列的兴起

能够说ECMAScript6是JavaScript历史上最大的一次变革,ES6的到来为JavaScrip带来了面向对象的特性,带来了许多新的语法,也让这门解释性语言有了它该有的样子。总的来讲,带来了无限好处。带来好处的同时也让咱们在用的时候有了担心,用户的角度是广阔的,开发者没法提早预知用户用的浏览器到底支持不支持ES6的语法,所以在开发过程当中就有个阻碍。babel的兴起让ES6的开发者大显身手,可是它是把ES6的语法编译成ES5的语法,也就是浏览器支持的语法。咱们要知道在ES6兴起的时候,V8引擎是对ES6语法有了极大的优化的,滥用了babel不就也放弃了这种优化吗?这使得ES6只让开发者更加便于开发,用户的角度上并无体现出任何价值,并且babel编译出的庞大的ES5文件,在用户方法还起到了负面做用。那这到底怎么办呢?接下来主角登场。javascript

最优的解决方案

emmmm...主角登场前,电闪雷鸣,乌云密布。当咱们在开发过程当中的时候,JavaScript采用两种文件的方式来加载。一种的ES6代码写的文件,一种的babel编译成ES5的文件。在浏览器中执行的时候,判断浏览器是否支持ES6,若是支持就加载ES6的文件,若是不支持就加载ES5的文件,这样就良好的解决问题。那么用什么判断呢?主角登场。。。。html

type='module'

在script标签里面咱们都知道有type属性指定文件的类型(type='text/script'),这个属性还有一个值那就是module和nomodule。java

  1. module:表示当浏览器支持ES6的时候执行的JavaScript代码
  2. nomodule:表示当浏览器不支持ES6的时候执行的JavaScript代码。

咱们在项目中建立test.js文件来写这样一段代码:当咱们在写好ES6的代码的时候不要直接调用,阮大佬的import,用ES6 import export的形式导出git

class Test {
    constructor(){
        this.name = 'zhangsan';
    }
    action(){
        console.log(this.name);
    }
}
export default Test;
复制代码

在html中:使用ES6的动态import的形式加载进来。es6

<script type='module'> import('test.js').then(_=>{ console.log('我支持modul'); new _.default().action(); }) </script>
复制代码

打开Chrom浏览器会发现有这样的一句输出github

type=‘nomodule’的状况下咱们执行babel编译npm

使用babel编译

安装babel浏览器

npm install --save-dev @babel/core @babel/cli @babel/preset-envbash

在项目根目录建立.babelrc文件,内容以下babel

{
    "presets" : ["@babel/preset-env"]
}
复制代码

使用命令进行编译

babel test.js --out-file test-bundle.js

test-bundle.js文件内容以下:

"use strict";
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Test =
/*#__PURE__*/
function () {
  function Test() {
    _classCallCheck(this, Test);

    this.name = 'zhangsan';
  }

  _createClass(Test, [{
    key: "action",
    value: function action() {
      console.log(this.name);
    }
  }]);

  return Test;
}();

var _default = Test;
exports.default = _default;

复制代码

咱们发现第二行使用的是模块加载export,require之类的东西,可是咱们浏览器中并无这些东西,因而咱们采用一个模块加载器来加载这个东西。

System.js

System.js是一个万能模块加载器,任何使用模块加载的均可以使用它来进行加载。用法也很是简单。Systemjs的github。咱们采用script标签的形式把这个东西加载进来。并用官网的方式加载test.js

须要注意的是:Systemjs必须指定nomodule,和ES5文件保持一致才能够。因为咱们用于测试和最新的Chrome浏览器确定是支持module的,因此先把nomodule改为module来用于测试

<!--<script type="nomodule" src="https://cdn.staticfile.org/systemjs/3.0.0/system.js"></script> <script type="nomodule"> System.import('test.js').then(_=>{ new _.default().action(); }) </script>-->
 
 <script type="module" src="https://cdn.staticfile.org/systemjs/3.0.0/system.js"></script>
 <script type="module"> System.import('test.js').then(_=>{ new _.default().action(); }) </script>
复制代码

打开浏览器见证奇迹

哎呀报错了,很懵逼,很焦虑,为何会报错呢? 由于babel编译的es5的语法采用的模块加载器是export加载,并无使用SystemJS的加载方式。能够经过babel插件来把babel的模块加载方式改为SystemJS的加载方式。

最后的但愿

咱们在npm上找到这个插件@babel/plugin-transform-modules-systemjs并安装

npm install @babel/plugin-transform-modules-systemjs --sav-dev

在.babelrc里面添加上plugins

{
    "presets" : ["@babel/preset-env"],
    "plugins" : ["@babel/plugin-transform-modules-systemjs"]
}
复制代码

此时使用上面babel语法进行编译,文件内容以下

"use strict";
System.register([], function (_export, _context) {
 "use strict";

  var Test;

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

  function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

  function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

  return {
    setters: [],
    execute: function () {
      Test =
      /*#__PURE__*/
      function () {
        function Test() {
          _classCallCheck(this, Test);

          this.name = 'zhangsan';
        }

        _createClass(Test, [{
          key: "action",
          value: function action() {
            console.log(this.name);
          }
        }]);

        return Test;
      }();

      _export("default", Test);
    }
  };
});
复制代码

第二行咱们发现有这样一个东西System.register([], function (_export, _context),与以前的编译不同了。此时就是使用SystemJS的模块加载机制。咱们打开浏览器。

完美。

在使用type=‘module’和和type=‘nomodule’的时候,必定要把SystemJS的type设置成nomodule,与ES5语法统一。


原文发表于浏览器支持ES6的最优解决方案

相关文章
相关标签/搜索