公司的项目都是 JSP 项目,而我自己喜欢使用 ES6 的一些语法,但是 ES6 的很多方法在 IE8 中不支持,查了资料,可以用 Babel 进行转码。
然而兼容 IE 会碰到很多问题:
- IE8 对 ES5 支持不好,一些代码得编译成 ES3。比如转换模块调用时候会出现
exports.default
,而default
是 IE8 中的关键字会异常。 - 缺少很多 API 如:
promise
、Object-assign
等。 - IE8 不完全支持
Object.defineProperty
。
Babel
Bable 初次使用
新建一个文件夹,初始化,装依赖
yarn init
yarn add @babel/core @babel/cli @babel/preset-env @babel/polyfill
yarn add core-js regenerator-runtime -D
# or
npm install --save-dev @babel/core @babel/cli @babel/preset-env
npm install --save @babel/polyfill core-js regenerator-runtime
新建文件 babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": "8"
},
"useBuiltIns": "usage",
"corejs": "3.6.4"
}
]
]
}
useBuiltIns
: 引入垫片的方式,一个是全局引入垫片,另一个是按需引入垫片,值可以是 entry
和 usage
,假如是 entry
会在入口处把所有 ie8 以上浏览器不支持 api 的 polyfill
引入进来
运行命令行将 src
文件夹的代码转换到 lib
文件夹
./node_modules/.bin/babel src --out-dir lib
也可以将
./node_modules/.bin/babel
换成npx babel
直接运行
测试代码如下:
class Hello {
static world() {
console.log("Hello, World!");
}
}
Hello.world();
let a = (data) => {
setTimeout(() => {
const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };
const returnedTarget = Object.assign(target, source);
console.log(target);
console.log(returnedTarget);
}, 500);
};
a("哈哈");
输出结果:
"use strict";
require("core-js/modules/es.object.assign");
require("core-js/modules/es.object.define-property");
require("core-js/modules/web.timers");
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 Hello = /*#__PURE__*/ (function () {
function Hello() {
_classCallCheck(this, Hello);
}
_createClass(Hello, null, [
{
key: "world",
value: function world() {
console.log("Hello, World!");
},
},
]);
return Hello;
})();
Hello.world();
var a = function a(data) {
setTimeout(function () {
var target = {
a: 1,
b: 2,
};
var source = {
b: 4,
c: 5,
};
var returnedTarget = Object.assign(target, source);
console.log(target);
console.log(returnedTarget);
}, 500);
};
这时候我发现了个问题,代码里面有 require("core-js/modules/es.object.assign");
在浏览器中无法运行。
查资料得知可能要用 webpack
或者 gulp
打包一下。
继续了解 Bable 插件
依稀记着 babel runtime
,webpack 的 bable-loader
,还有 plugin-transform-runtime
可能可以给我带来一些帮助
@babel/plugin-transform-runtime
@babel/plugin-transform-runtime
一个插件,可重新使用 Babel 注入的帮助程序代码以节省代码大小。
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
配置文件加
{
"plugins": ["@babel/plugin-transform-runtime"]
}
这次,代码发生了一些的变化,具体细节就不说了,因为我也不是很懂说不清
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/es.object.assign");
require("core-js/modules/web.timers");
var _classCallCheck2 = _interopRequireDefault(
require("@babel/runtime/helpers/classCallCheck")
);
var _createClass2 = _interopRequireDefault(
require("@babel/runtime/helpers/createClass")
);
var Hello = /*#__PURE__*/ (function () {
function Hello() {
(0, _classCallCheck2["default"])(this, Hello);
}
(0, _createClass2["default"])(Hello, null, [
{
key: "world",
value: function world() {
console.log("Hello, World!");
},
},
]);
return Hello;
})();
Hello.world();
var a = function a(data) {
setTimeout(function () {
var target = {
a: 1,
b: 2,
};
var source = {
b: 4,
c: 5,
};
var returnedTarget = Object.assign(target, source);
console.log(target);
console.log(returnedTarget);
}, 500);
};
a("haha");
@babel/plugin-transform-object-assign
使用 @babel/plugin-transform-object-assign
测试
@babel/plugin-transform-object-assign
发现 Object.assign
没有了
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/web.timers");
var _extends2 = _interopRequireDefault(
require("@babel/runtime/helpers/extends")
);
var _classCallCheck2 = _interopRequireDefault(
require("@babel/runtime/helpers/classCallCheck")
);
var _createClass2 = _interopRequireDefault(
require("@babel/runtime/helpers/createClass")
);
var Hello = /*#__PURE__*/ (function () {
function Hello() {
(0, _classCallCheck2["default"])(this, Hello);
}
(0, _createClass2["default"])(Hello, null, [
{
key: "world",
value: function world() {
console.log("Hello, World!");
},
},
]);
return Hello;
})();
Hello.world();
var a = function a(data) {
setTimeout(function () {
var target = {
a: 1,
b: 2,
};
var source = {
b: 4,
c: 5,
};
var returnedTarget = (0, _extends2["default"])(target, source);
console.log(target);
console.log(returnedTarget);
}, 500);
};
Webpack
看了 webpack 入门 这篇文章
运行 npm install webpack webpack-cli --save-dev
命令安装 webpack 依赖
创建 webpack 配置文件 webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
};
package.json
加入下面代码,用来运行 webpack 脚本
"scripts": {
"build": "webpack",
"dev": "webpack"
},
使用下面的命令转换
npm run build
#or
yarn build
踩坑
缺少标识符
如图,一路 debug,发现 default
是 ie8 的关键字,不能使用。
网上查了一圈,加自己动手实践,方法有 2 个,最方便的是 webpack 的配置里加下面的代码,其中 UglifyJsPlugin
的 uglifyOptions
内 的 ie8
参数默认是 false
,改成 true
就可以了。
安装依赖 uglifyjs-webpack-plugin
npm i -D uglifyjs-webpack-plugin
配置文件
const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
ie8: true,
},
}),
],
},
};
另一个是用 es3ify-loader
可以实现下面的效果
function(t) { return t.default; } // 编译前
function(t) { return t["default"]; } // 编译后
{ catch:function(t){} } // 编译前
{ "catch":function(t){} } // 编译后
配置文件如下
const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
optimization: {
minimize: false,
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
ie8: true,
},
}),
],
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ["es3ify-loader"],
},
],
},
};
还有个 es5-shim
的垫片,不过我没太看,没试验
对象不支持该操作
查了一下,是 object.defineProperty
在 ie8 中存在,但是只用用于操作 dom 对象
IE8 这波操作秀的我脑瓜子嗡嗡的,又想起来 vue 不支持 IE8 好像就是这个原因。
解决方法很多,比如加垫片。
运行命令行装依赖
npm i object-defineproperty-ie8
npm i core-js
require("object-defineproperty-ie8");
// 或者按需引入 core-js 的 define-property
require("core-js/features/object/define-property");
object-defineproperty-ie8
是司徒正美大佬写的,你们可以看看他的 github: object-defineproperty-ie8
另外就是装这两个插件也可以在一定程度上解决问题
最终代码
package.json
{
"name": "1",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"build": "webpack",
"dev": "webpack"
},
"devDependencies": {
"@babel/cli": "^7.11.6",
"@babel/core": "^7.11.6",
"@babel/plugin-transform-modules-commonjs": "^7.10.4",
"@babel/plugin-transform-object-assign": "^7.10.4",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/register": "^7.11.5",
"babel-loader": "^8.1.0",
"babel-plugin-transform-es2015-modules-simple-commonjs": "^0.3.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
},
"dependencies": {
"@babel/polyfill": "^7.11.5",
"@babel/runtime": "^7.11.2",
"core-js": "^3.6.5",
"es3ify-loader": "^0.2.0",
"object-defineproperty-ie8": "^1.0.1"
}
}
webpack.config.js
const path = require("path");
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
module.exports = {
entry: "./src/index.js",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
optimization: {
minimize: false,
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
ie8: true,
},
}),
],
},
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"@babel/env",
{
targets: {
ie: "8",
},
useBuiltIns: "entry",
corejs: "3.6.4",
debug: true,
},
],
],
plugins: [
"@babel/plugin-transform-runtime",
"@babel/plugin-transform-object-assign",
"@babel/plugin-transform-modules-commonjs",
"transform-es2015-modules-simple-commonjs",
],
},
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ["es3ify-loader"],
},
],
},
};
babel.config.json
{
"presets": [
[
"@babel/env",
{
"targets": {
"edge": "17",
"ie": "8",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.4"
}
]
],
"plugins": [
"@babel/plugin-transform-runtime",
"@babel/plugin-transform-object-assign"
]
}
相关资料
参考文章
感谢这些前辈帮忙踩坑,让我有资料可查
- 风动之石的博客
- 一外国 babel 教程,非常完整,但是有点老
- 记一次 webpack4.x 打包兼容 ie8 的经历
- webpack4 编译代码如何完美适配 IE 内核
- 让 Webpack+Babel 支持 IE8
资源
司徒正美大佬的垫片:object-defineproperty-ie8
学习的时候搜索的关键词
babel
基础babel example
找相关例子polyfill
垫片browserslist
浏览器支持stage-0 stage-1 stage-2 stage-3
都是做什么的babel-cli
怎么用babel-core
怎么用webpack babel-loader
怎么配置
Github 地址
实战
有个项目,以前我做过 babel 转 es6 加垫片,然后我忘了,我再实验一下
就是这个,这个是个非常好使的拖拽多选组件,越用越香,越用越好使,然而不支持 IE8。
后面有时间再弄,先空着
总结
学习了 webpack 和 babel,收获蛮多的。