Некоторое время назад был рефакторинг очень интересного проекта, который представляет собой SDK для сбора данных, основанный на среде браузера. Этот SDK встроен в интерфейсные страницы каждого продукта компании для сбора данных о поведении пользователей и загрузки их на платформу больших данных компании, чтобы обеспечить поддержку данных для последующего оперативного анализа решений.
Когда автор взялся за этот проект, предыдущий разработчик уже написал почти все функции. Единственное, что необходимо сделать, это выполнить модульное разделение и спецификацию кода для последующей разработки и обслуживания. Webpack используется для модульного разделения, а eslint — для спецификации кода. Поскольку вы хотите провести рефакторинг, давайте перепишем его с помощью es6. Колбэки больше не нужны, их все заменили промисами, а также используются асинхронность и ожидание, в любом случае, как их написать — это круто.
Спросите у ПМ, с какой версией хотя бы совместим браузер, ПМ скажет, что он совместим с минимальной версией, совместимой с различными продуктами компании. Пообщавшись с лицом, ответственным за различные продукты компании, я обнаружил, что на самом деле существует совместимый IE8, что меня совершенно не устраивает.
Я погуглил, что Webpack+Babel+ES6 совместим с IE8, и там много подводных камней. Я пробовал решения, приведенные в нескольких блогах, но ни одно из них не работает. Я мало изучал конкретные проблемы, потому что webpack и babel в этих решениях — старые версии, и их не любят использовать. Автор анализирует несколько ключевых вопросов, затронутых в этих блогах, а затем обращается к последним официальным документам webpack и babel и резюмирует набор последних совместимых с Webpack4+Babel7+ES6 решений IE8.
Совместимость ES6 с IE8 должна решить четыре проблемы
Поддержка синтаксиса
Браузер IE не поддерживает синтаксис ES6 и поддерживает только некоторые API ES6 в IE10 и IE11.Поэтому использование ES6 в браузере IE требует перед выполнением компиляции кода ES6 в ES5. Метод также очень прост, просто используйтеbabel-loader
. Ям в этой части нет, поэтому не буду вдаваться в подробности. Дайте сайт, вы сами можете проверить поддержку ES5 и ES6 в каждой версии браузера
Смотреть Kaxiu.GitHub.IO/com pat-Он изначально был…
Зарезервированные ключевые слова ES3
Если передается под IE8object.propertyName
способ использовать зарезервированные ключевые слова в ES3 (например,default、class、catch
), будет выдано сообщение об ошибке
SCRIPT1048: 缺少标识符
webpack имеет плагин загрузчикаes3ify-loader
Специально разработан для решения проблем совместимости ключевых слов ES3. Роль этого плагина заключается в том, чтобы заключить для вас эти зарезервированные слова в кавычки и процитировать их в виде строк.
// 编译前
function(t) { return t.default; }
// 编译后
function(t) { return t["default"]; }
Однако, после моей собственной практики, я обнаружил, чтоUglifyJS
Поддержка браузера IE уже предусмотрена, дополнительного ознакомления не требуетсяes3ify-loader
. веб-пакет по умолчаниюUglifyJS
Конфигурация не поддерживает ie8 и требует ручной настройки.
{
mode: 'production',
optimization: {
minimizer: [
new UglifyJsPlugin({
uglifyOptions: {
ie8: true
}
})
]
}
}
среда исполнения
Решение первых двух проблем может гарантировать только отсутствие грамматической ошибки, но использование API в ES6 (например,Promise
) все равно будет сообщать об ошибке. Кроме того, поддержка API IE8 для ES5 также очень плохая, поддерживается лишь небольшое количество API, а некоторые API поддерживают только некоторые функции (например,Object.defineProperty
). Итак, чтобы код ES6 идеально работал в IE8, нужно заполнить не только ES6 API, но и ES5 API.
Babel предлагает два решения для этого:@babel/polyfill,@babel/runtime. Официальная документация конкретного метода использования написана очень подробно, поэтому я не буду вдаваться в подробности. Студенты, которые хотят понять разницу между ними, могут прочитать статью Мобаи из Dasouche,babel-polyfill VS babel-runtime
Здесь, чтобы исправить ошибку в эссе Мо Бая, то есть@babel/polyfill
Теперь поддерживается загрузка по требованию, точнее, это нельзя считать ошибкой, потому что Mo Bai не поддерживал загрузку по требованию при написании этой статьи. Не буду подробно останавливаться на конкретном методе, все есть в документации, настраивайтеbrowserlistа также@babel/preset-env
изuseBuiltsIns
свойства в порядке.
Я говорю только о ямах, с которыми я столкнулся в реальном процессе разработки.
несмотря на то что@babel/polyfill
,@babel/runtime
Оба поддерживают загрузку по требованию, но они могут только идентифицировать отсутствующие API, используемые в бизнес-коде.Если сторонние библиотеки используют эти отсутствующие API, Babel не может их идентифицировать, и, естественно, они не могут быть заполнены. Напримерregenerator-runtime
используется вObject.create
а такжеArray.prototype.forEach
. Решение состоит в том, чтобы вручную ввести отсутствующий API в файл входа.
Модульная загрузка
Первоначально автор хотел использовать модульную схему загрузки ES6, потому что она может использовать преимущества веб-пакета.tree shaking, удалите лишний код и уменьшите упакованный файл. Но тестирование в IE8 показало, что Object.defineProperty сообщит об ошибке'Accessors not supported!'
.报错代码如下
if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported!');
я использую@babel/plugin-transform-modules-commonjsПереход на загрузку commonjs может обойти эту яму, но это также означает отказ отtree shaking
.
Суммировать
package.json
{
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.1.0",
"@babel/runtime": "^7.3.4",
"babel-loader": "^8.0.4",
"core-js": "^3.0.1",
"uglifyjs-webpack-plugin": "^2.0.1",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.9",
"webpack-merge": "^4.1.4"
}
}
конфигурация веб-пакета
{
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env'
],
plugins: [
[
'@babel/plugin-transform-runtime'
],
[
// 笔者为了兼容IE8才用了这个插件,代价是不能tree shaking
// 没有IE8兼容需求的同学可以把这个插件去掉
'@babel/plugin-transform-modules-commonjs'
]
]
}
}
}
]
},
optimization: {
minimizer: [
new UglifyJsPlugin({
sourceMap: true,
uglifyOptions: {
ie8: true,
}
})
]
}
}
Файлы ввода вводят отсутствующие API по мере необходимости.
require('core-js/features/object/define-property')
require('core-js/features/object/create')
require('core-js/features/object/assign')
require('core-js/features/array/for-each')
require('core-js/features/array/index-of')
require('core-js/features/function/bind')
require('core-js/features/promise')
Наконец, исходный код sdk, упомянутый в начале статьи, прилагается.Автор удалил код, связанный с бизнесом компании, и сделал общую часть с открытым исходным кодом.GitHub.com/xt Tech / Для этого - да ...