兼容ie8这几天弄的我真是焦头烂额啊,连摸带爬,掘金,csdn,博客园,segmentfault。辗转多个平台,翻阅多个文章,最终算是完美兼容。
首先是我的package.json
{
"name": "webpack-init",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"package": "npx webpack"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"handlebars-loader": "^1.7.1",
"jquery": "1.12.4",
"jquery-ui": "^1.13.0"
},
"devDependencies": {
"@babel/cli": "^7.5.0",
"@babel/core": "^7.5.0",
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
"@babel/plugin-transform-object-assign": "^7.2.0",
"@babel/plugin-transform-runtime": "^7.16.7",
"@babel/preset-env": "^7.5.0",
"@types/jquery": "^3.5.11",
"babel-loader": "^8.0.6",
"clean-webpack-plugin": "^4.0.0",
"core-js": "^3.20.2",
"css-loader": "^5.2.7",
"css-minimizer-webpack-plugin": "^1.3.0",
"expose-loader": "^1.0.3",
"file-loader": "^6.2.0",
"html-loader": "^1.3.2",
"html-webpack-plugin": "^3.2.0",
"less-loader": "^7.3.0",
"mini-css-extract-plugin": "^1.6.2",
"prettier": "^1.18.2",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^4.2.3",
"thbs-loader": "^1.0.1",
"ts-loader": "^8.3.0",
"typescript": "^3.6.0",
"uglifyjs-webpack-plugin": "^2.2.0",
"url-loader": "^4.1.1",
"webpack": "^4.35.2",
"webpack-cli": "^3.3.5",
"webpack-dev-server": "^3.7.2"
},
"browserslist": [
"defaults",
"ie 8"
]
}
然后是我的 tsconfig.json
{
"compilerOptions": {
"module": "ES6",
"target": "es5",
"sourceMap": false,
"moduleResolution": "Node"
},
"exclude": [
"node_modules"
],
"include": ["src", "types"]
}
最后是我的webpack.config.js
const path = require("path")
const htmlWebpackPlugin = require("html-webpack-plugin")
const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
const {CleanWebpackPlugin} = require("clean-webpack-plugin")
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const projectConfig = require("./projectConfig.json")
let entry = {}, html = []
pre_process()
module.exports = {
mode: "production",
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
terserOptions: {
ie8: true,
mangle: true,
output: {
comments: false //是否有注释
},
compress: {
properties: false,
drop_console: false,
warnings: false //是否显示警告
},
},
extractComments: false,
}),
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
'default',
{
discardComments: {
removeAll:true
}
}
]
}
})
],
},
entry: entry,
output: {
path: path.resolve(__dirname, "dist"),
filename: "app/[name]/[name]-[hash:8].js",
chunkFilename: "./router/public_[chunkhash:8].js"
},
module: {
noParse: [/jQuery/],
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader",
options: {
presets: [['@babel/preset-env', {
"useBuiltIns": "entry",
corejs: 3
}]],
plugins: [
['@babel/plugin-transform-modules-commonjs']
]
}
}]
},
{
test: /\.less$/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'less-loader'
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ['$', 'jQuery']
}
},
{
test: /.hbs$/i,
loader: "handlebars-loader?helperDirs[]=" + __dirname + "/src/hbsHelps",
options: {}
},
{
test: /.ts$/i,
use: [
{loader: "ts-loader"}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: 'url-loader',
options: {
limit: 10 * 1024,
name: 'assets/[name].[ext]',
}
}
},
{
test: /\.html$/i,
loader: "html-loader",
options: {
minimize: false
}
},
]
},
target: "web",
plugins: [
...html,
new MiniCssExtractPlugin({
filename: "styles/[name]_[chunkhash:8].css",
}),
new CleanWebpackPlugin()
],
resolve: {
extensions: [".js", ".ts"]
}
}
function pre_process() {
if (projectConfig.components) {
for (let key in projectConfig.components) {
entry[key] = [].concat([projectConfig.components[key].js])
entry[key] = entry[key].concat([projectConfig.components[key].css])
html.push(new htmlWebpackPlugin({
template: projectConfig.components[key].html,
chunks: [key, ...projectConfig.components[key]['vendorJs']],
chunksSortMode: function (a, b) {
if (a['names'][0].indexOf("common") !== -1) {
return -1
}
return 1
},
filename: key + ".html"
}))
}
}
if (projectConfig.js) {
for (let key in projectConfig.js) {
entry[key] = projectConfig.js[key]
}
}
for (const key in entry) {
if (projectConfig.components[key] && projectConfig.components[key]['vendorCss'].length > 0) {
let cssArray = projectConfig.components[key]['vendorCss'];
for (const ele of cssArray) {
entry[key] = [...entry[key], ...projectConfig.css[ele]];
}
}
}
}
重点
我引入了json来简化项目的配置,具体可见webpack.config.js line 7 ,具体实现可以看 pre_process()函数
具体配置如下:
{
"components": {
"index": {
"html": "./src/index.html",
"css": "./src/index.less",
"js": "./src/index.ts",
"vendorJs": [
"common"
],
"vendorCss": ["common"]
},
"home": {
"html": "./src/Home/index.html",
"css": "./src/Home/home.less",
"js": "./src/Home/home.js",
"vendorJs": [
"common"
],
"vendorCss": []
}
},
"js": {
"common": [
"./node_modules/core-js/stable/index.js",
"./node_modules/jquery/dist/jquery.min.js",
"./node_modules/jquery-ui/ui/core.js"
]
},
"css": {
"common": [
"./node_modules/jquery-ui/themes/base/button.css",
"./node_modules/jquery-ui/themes/base/theme.css"
]
}
}
此配置如何使用?
首先 components 下面是每一个模块,vendorJs是公共的js模块,例如jquery,jquery-ui,core-js可以放在这里,vendorJs引用了js下面的值,同理,vendorCss亦然如此。
为什么引用core-js?
core-js是babel官方用来替代babel-plyfill的新垫片,此垫片可以解决ie8下 Object.defineProperty()
以及不支持的新API,例如 String.prototype.startsWith()
,诸如此类
目录结构
简书2022-1-5 ie8.jpg
不足之处
- 项目对于文件处理能力不足
- webpack.config.js仍有待简化处理
开源
项目已经开源,地址为 https://gitee.com/MelancholyAstronaut/webpack4-ie8