web3.0 升级到webpack5.0 以及兼容IE处理

如果你的事vue-cli  或者其他cli 关于IE 兼容不具有什么参考价值。如果是react 项目,你看看就行。

webpack3的打包速度已成为诟病,所以我们将原来的webpack3升级至webpack5

首先就是原来的项目结构,主要在于build目录下面,存在基础配置,开发配置,生产配置
build
|-------util.js
|-------webpack.common.js
|-------webpack.dev.js
|-------webpack.prod.conf.js

升级webpack和相应插件 

首先,卸载原有的webpack

  • 安装webpack 5.0

                npm install webpack  webpack-dev-server   webpack-cli

     安装完成以后

  • 升级其他插件版本 安装npm-check-updates

      npm install -g npm-check-updates

     安装完成以后执行npm-check-updates,

修改 package.json 文件到相应的版本。

执行  npm cache clean -f   , 删除node-modules   执行npm install,

此时会报各种版本不匹配,一定要降级,除了webpack  版本维持不动以外,其他版本尽量往下降

以上升级完成以后。除了IE 以外都可以正常运行了。

IE兼容处理

webpack 5.0 以后,IE 兼容参考babel-preset  官方文档。IE 的兼容一言难进,特别是webpack3,升级到webpack5.0以后,webpack3的兼容写法全部报废。

个人意见如下:

1. 使用core-js   如果你的代码有用到Map Set   symbol 等新特性建议使用core-js3.0 如果没有用到core-js2.0

2. webpack3.0  一系列babel- 的插件, 除 babel-loader 以外。其他都要替换成@babel-开头的(版本不是越新越好core-js2 和core-js3 npm 版本库看发布日期,下载时候下年限差不多的就行。)

3. webapck 打包输出,output:[core-js,main.js]  网上还有其他方案, 个人兼容如果是core-js2.0.0 使用这个,如果是安装的是core-js3.0。可以尝试网上其他答案。

4. 插件注意 @babel/plugin-transform-runtime   是做promise 兼容处理的,内部core-js配置 和上一步core-js 版本没有任何关系。下载完成之后看node_modules 这个插件使用的是core-js 第几个版本 就在.babelrc 配置第几个。

5.IE兼容如果出错了,在IE 预览时,一般都会明确的指向node_modules 那个包,或者是你内部代码哪里写的又问题,一定要记住千万不要去改相关代码, babel-preset  官网找到相应插件解析, 如果node_modules 中的 包又问题,就降版本,降版本,降版本。

6. 第三方引入的静态文件,这一类的如果是,index.html 之间标签引入两个建议1.要么放到cdn 独立的加速服务器,要么统一放到本地的一个文件夹(static) 这个文件夹千万不要 使用babel-loader 再次解析,IE 会出现很多莫名的错误(这一点坑了我很久)

IE 浏览器兼容就是以上所述,如果其他大佬有补充请留言

配置源码说明

 代码文件有部分注释,可以关注一下也许对你有一定的帮助

webpack.dll.config.js

文件如下 ----dll 打包具体怎么操作可以参考webpack 官网,不过现在都是各种cli 单独使用webpack 已经很少了

const path = require('path');
const webpack = require('webpack');
const presetEnv=require("@babel/preset-env")
module.exports = {
  mode: "production",
  target: ['web', 'es5', "browserslist"], // 要加这个,这是webpack5.0 的新特性。
  entry: {
    vendor: [  // 这里是dll 公共打包的。看自己需求,可以放更多。
      'vue',    
      'vue-router',
      'vuex',
      'vue-i18n',
      'axios',
      'vuex-persistedstate'
    ]
  },
  output: {
    path: path.join(__dirname, '../static/js/dll'),
    filename: '[name].dll.js',
    library: '[name]_library',      // vendor.dll.js中暴露出的全局变量名
    clean:true,
    environment: {
      arrowFunction: false
    }
  },
  plugins: [
    new webpack.DllPlugin({
      path: path.join(__dirname, '.', '[name]-manifest.json'),
      name: '[name]_library',
      context: path.resolve(__dirname, '..')
    })
  ],
  module:{
    rules:[{
      test:/\.js$/,
      use:{
        loader:'babel-loader',
        options:{
          presets:[presetEnv],
        }
      }
    }]
  }
};

webpack.dev.js

const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');

module.exports = merge(common, {
  mode: 'development',
  devtool: 'inline-source-map', // IE 会自动解析Map 对于兼容调试很有帮助。
  devServer: {
  },
  module: {
    rules: [
      {
        test: /.css$/,
        use: ["style-loader","css-loader"],
      },
      {
        test: /.less$/,
        use: ["style-loader",'css-loader', 'less-loader'],
      },
    ],
  },
});

webpack.common.js  打包基础核心

const path = require("path");
const { DefinePlugin, DllReferencePlugin } = require('webpack') //dll 打包必须如果不是可以去掉
const HtmlWebpackPlugin = require("html-webpack-plugin"); // 模版主体 没有太大的变化。
const VueLoaderPlugin = require('vue-loader/lib/plugin'); // webpack5.0 vue-loader 的配置方式改变了 主意pagejson版本 
const utils = require('./utils') 
const WebpackBar = require('webpackbar'); // 打包进度条。默认的很不错,更多 可以参考npm库。
module.exports = {
  target: ['web', 'es5', "browserslist"],
  entry: {
    app: ['core-js',"./src/main.js"], // 兼容IE 必须, 如果IE 不需要可以将core-js 删除
  },
  output: {
    filename: "[name].[contenthash].js",
    path: path.resolve(__dirname, "../dist"),
    chunkFilename: "[name].[contenthash].js",
    clean: true,
    publicPath: utils.commonCofig.assetsPublicPath,
    pathinfo: utils.commonCofig.pathinfo,
    enabledWasmLoadingTypes: ['fetch'],
    environment: {
      templateLiteral: false, // 默认是true
      optionalChaining: false, // 默认是true
      module: true, // 默认是false
      forOf: false, // 默认是true
      dynamicImport: false, // 默认是false,
      // dynamicImportInWorker:false, // 默认是false,
      destructuring: false,// 默认是true
      const: false,// 默认是true
      bigIntLiteral: false,// 默认是false
      arrowFunction: false // 默认是true
    }
  },
  resolve: {
    extensions: [".*", '.js', '.vue', ".json"],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': path.resolve(__dirname, "../src"),
      '@static': path.resolve(__dirname, "../static"),
      '@common': path.resolve(__dirname, "../src/common"),
      '@components': path.resolve(__dirname, "../src/components"),
      '@pages': path.resolve(__dirname, "../src/pages"),
      '@assets': path.resolve(__dirname, "../src/assets"),
    }
  },
  plugins: [
    new HtmlWebpackPlugin({
      title: "Production",
      template: './public/index.html',
      hash: true,
      inject: true
    }),
    new DefinePlugin({
      process: {
        env: JSON.stringify({ ...utils.commonCofig.env })
      },
      '_basepath_': JSON.stringify(utils.commonCofig.assetsPublicPath)
    }),
    new VueLoaderPlugin(),
    new DllReferencePlugin({
      context: path.resolve(__dirname, '..'),
      manifest: require('./vendor-manifest.json')
    }),
    new WebpackBar(),
  ],


  optimization: {
    moduleIds: "deterministic",
    runtimeChunk: "single",
    splitChunks: {
      chunks: "all",
      cacheGroups: {
        vendeor: {
          test: /[\\/]node_modules[\\/]/,
          name: "vendeors",
          chunks: "all",
        }
      }
    }
  },


  module: {
    rules: [
      {
        test: /\.vue$/,
        include: path.resolve(__dirname, "../src"),
        use: [
          "vue-loader",
        ]
      },
      {
        test: /\.(js|vue)$/,
        include: path.resolve(__dirname, "../src"),
        // exclude: /(node_modules|static)/,
        use: [
          {
            loader: 'thread-loader',
            options: {
              workers: 40,
            }
          }]
      },
      {
        test: /\.(js)$/,
        include: path.resolve(__dirname, "../src"),
        exclude: /(static|node_modules)/,      // iE兼容 一定加上static 第三方插件压缩js引用。
        use: {
          loader: "babel-loader",
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        type: "asset/resource",
        generator: {
          filename: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        type: "asset/resource",
        generator: {
          filename: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }, {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: "pre",
        include: [path.resolve(__dirname, "../src")],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      }
    ]
  }
}; 

webpack.prod.js

const { merge } = require("webpack-merge");
const path = require('path')
const common = require("./webpack.common.js");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
const CopyWebpackPlugin = require('copy-webpack-plugin')
const config = require('../config')
const utils = require('./utils')
const WebpackBar = require('webpackbar')


module.exports = merge(common, {
  mode: "production",
  // devtool: "source-map",
  module: {
    rules: [
      {
        test: /.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
      },
      {
        test: /.less$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
      },
    ],
  },
  optimization: {
    minimizer: [
      new CssMinimizerPlugin()
    ]
  },
  devtool: config.build.productionSourceMap || 'source-map',
  output: {
    path: config.build.assetsRoot,
    filename: utils.assetsPath('js/[name].[chunkhash].js'),
    chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename:  utils.assetsPath('css/[name].[chunkhash].css'),
      chunkFilename: utils.assetsPath('css/[id].[chunkhash].css')
    }),
    new CopyWebpackPlugin({ // 静态资源拷贝一定要有。
      patterns: [{
        from: path.resolve(__dirname, '../static'),
        to: config.build.assetsSubDirectory,
      }]
    }),
    new WebpackBar(),
  ],
  optimization: { // 样式分包,每一个组件的私有样式都会打一个单独的样式包。好坏不做评价
    splitChunks: {
      cacheGroups: {
        fooStyles: {
          type: 'css/min-extract',
          name: "styles_foo",
          chunks: (chunk) => {
            return chunk.name === "foo"
          },
          enforce: true,
        },
        barStyles: {
          type: 'css/min-extract',
          name: "styles_bar",
          chunks: (chunk) => {
            return chunk.name === 'bar';
          },
          enforce: true,
        }


      }
    }
  }
});

util.js  配置  // 核心是为了区分环境,如果想自定义变量参考文档 

Environment 选项-webpack5.0 APi

环境变量---webpack5.0指南

内置环境变量--node缓存设置。这个个人感觉比较有用,所有记录一下。

const path = require('path')
const config = require('../config')
// 未使用webpack 注入变量, webpack5.0 有很多新特性的变量,参考官网
// npm_lifecycle_event  是取 npm run [name] 的name 字符。
const isProduction = process.env.npm_lifecycle_event !== 'dev' 
exports.assetsPath = function (_path) {
  const assetsSubDirectory = isProduction
    ? config.build.assetsSubDirectory
    : config.dev.assetsSubDirectory
  return path.posix.join(assetsSubDirectory, _path)
}
exports.commonCofig = isProduction? config.build : config.dev

config/index.js 问配置

const path=require('path')

module.exports={
 build:{
   index:path.resolve(__dirname,'../dist/index.html'),
   assetsRoot:path.resolve(__dirname,'../dist'),
   assetsSubDirectory:'./static',
   assetsPublicPath:'/prefixName/', //这个是线上服务器配置的,域名/prefixName/页面路由
   productionSourceMap:false,
 },
 dev:{
  port:8080,
  autoOpenBrowser:true,
 assetsSubDirectory:'static',
 assetsPublicPath:'/',
 proxytable:{ //本地调试接口代理配置。每个项目都不一样,没有参考价值我就不放了
 },
 cssSourceMap:true
 }
}

.babelrc-----babel-lodaer 的配置, 主要是IE 兼容处理,如果没有这个,IE会是空白页面(报js错误。)

{
    "presets": [
      [
        "@babel/preset-env"
      ]
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "corejs": 3
        }
      ],
      "@babel/plugin-transform-property-mutators",
      "@babel/plugin-transform-arrow-functions",
      "@babel/plugin-transform-parameters"
    ]
  }

package.json 文件如下,

npm install之后,一定要执行npx browserslist 查看一下支持的浏览器列表。如何配置请查看browserslist git

{
  "name": "webpack5",
  "version": "1.0.0",
  "sideEffects": true,
  "description": "",
  "private": true,
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "server": "node ./build/server.js",  //模拟线上环境
    "dev": "webpack serve --open --config ./build/webpack.dev.js",
    "build": "webpack --config ./build/webpack.prod.js",
    "watch": "webpack --watch"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.18.10",
    "@babel/core": "^7.22.5",
    "@babel/plugin-transform-arrow-functions": "^7.18.6",
    "@babel/plugin-transform-parameters": "^7.22.5",
    "@babel/plugin-transform-property-mutators": "^7.16.7",
    "@babel/plugin-transform-runtime": "^7.0.0",
    "@babel/preset-env": "^7.20.2",
    "@babel/runtime-corejs3": "^7.22.5",
    "@types/js-cookie": "^3.0.2",
    "axios": "^1.2.2",
    "babel-loader": "^9.1.0",
    "copy-webpack-plugin": "^11.0.0",
    "core-js": "^2.6.12",
    "crypto-js": "^3.3.0",
    "css-loader": "^6.7.3",
    "css-minimizer-webpack-plugin": "^4.0.0",
    "eslint": "^7.32.0",
    "eslint-friendly-formatter": "^4.0.1",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-vue": "^9.8.0",
    "eslint-webpack-plugin": "^3.2.0",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.18.2",
    "html-webpack-plugin": "^5.5.0",
    "js-cookie": "^2.2.1",
    "less": "^4.1.3",
    "less-loader": "^10.2.0",
    "md5": "^2.3.0",
    "mini-css-extract-plugin": "^2.6.1",
    "normalize.css": "^8.0.1",
    "style-loader": "^3.3.1",
    "thread-loader": "^3.0.4",
    "vue": "^2.7.14",
    "vue-loader": "^15.10.0",
    "vue-loader-plugin": "^1.3.0",
    "vue-router": "^2.7.0",
    "vue-template-compiler": "^2.7.14",
    "vuex": "^2.5.0",
    "vuex-persistedstate": "^1.3.0",
    "webpack": "^5.88.1",
    "webpack-cli": "^4.10.0",
    "webpack-dev-middleware": "^5.3.3",
    "webpack-dev-server": "^3.11.3",
    "webpack-hot-middleware": "^2.25.1",
    "webpackbar": "^5.0.2"
  },
  "browserslist": "> 0.1%,not dead,last 3 version",
  "dependencies": {
    "vue-loader": "^15.10.0"
  }
}

附件build/server.js // 主要是模拟生产环境在本地运行。

const  express=require('express')
const webpack=require('webpack')
const webpackDevmiddleWare=('webpack-dev-middleware')
const app=express()
const config=require('./webpack.prod')
const compiler=webpack(config)

app.user(webpackDevmiddleWare(compiler,{
    publicPath:config.output.publicPath
}))

app.listen(3000,function(){
 console.log("Exaplae app listening on port 3000!\n")

})

你可能感兴趣的:(webpack,webpack5.0,IE兼容处理)