webpack4 + babel7 + ts + less 兼容IE8最终章!!

兼容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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容