6#webpack插件2 @babel/polyfill mini-css-extract-plugin babel-loader

webpack插件@babel/polyfill mini-css-extract-plugin babel-loader

拆分webpack配置文件后,和正常項目的結(jié)構(gòu)更接近了,但是還有不是缺少幾個關(guān)鍵的插件。

1. css樣式分離成獨立的文件,并不會壓縮css代碼

1.extract-text-webpack-plugin
2.mini-css-extract-plugin

extract-text-webpack-plugin配置好后,npm run dev執(zhí)行后,發(fā)現(xiàn)報錯:

$ webpack
(node:18800) DeprecationWarning: Tapable.plugin is deprecated. Use new API on `.hooks` instead
C:\Users\EEE\AppData\Roaming\npm\node_modules\webpack\lib\Chunk.js:752
                throw new Error(
                ^

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
......

百度一查,據(jù)說是版本問題,咱也不懂,又去git倉庫查看了一下這個插件,發(fā)現(xiàn)好長一段時間沒更新過了,既然這樣直接放棄,換一個。
換成mini-css-extract-plugin這個插件,功能是一樣的。

#webpack.common.js

把module.rules里面css打包的那一段代碼注釋。

#webpack.dev.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = true;

plugins: [
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('development')
    }),
    new MiniCssExtractPlugin({
      // Options similar to the same options in webpackOptions.output
      // both options are optional
      filename: devMode ? '[name].css' : '[name].[hash].css',
      chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
    })
  ],
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader'
          /*,
          'postcss-loader',
          'sass-loader',*/
        ]
      }
    ]
  }

#webpack.prod.js
#mini-css-extract-plugin 本身不具有壓縮css代碼的功能,所以需要添加下面兩個插件配合
#npm install --save-dev terser-webpack-plugin optimize-css-assets-webpack-plugin
const TerserJSPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
    ......
  ],
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader']
      }
    ]
  }

2.babel-loader

npm install babel-loader @babel/core @babel/preset-env --save-dev

babel-loader7/8 要和 @babel/core ,@babel/preset-env 搭配使用,babel-loader6則使用babel-core/babel-preset-env。
@babel/preset-env 或 babel-preset-env // 有了它,你不再需要添加2015、2016、2017,全都支持。

# .babelrc (文件名不要搞錯了)
{
    "presets": [
        ["@babel/preset-env",{
            "targets": {
                "browsers": ["> 1%", "last 2 versions"]
            }
        }]
    ]
}

.babelrc文件,babel-loader8必須使用對應(yīng)的"@babel/preset-env",低于babel-loader8可以用"env"。

# webpack.common.js
module: {
    rules: [
      {
        test: /\.js$/,
        use: {
            loader: 'babel-loader'
        },
        // 不希望babel處理的 node_modules 目錄下的文件
        // UglifyJsPlugin不能壓縮es6,如果過濾這個目錄,
        // 可能會導(dǎo)致node_modules里面的es6代碼不能轉(zhuǎn)換導(dǎo)致壓縮報錯
        // exclude: '/node_modules/'
      },
      ......
  ]
}

到了這一步好像已經(jīng)OK了,已經(jīng)可以把es6轉(zhuǎn)換成es5了,但如果你在頁面里面用了promise,你就會發(fā)現(xiàn),好像轉(zhuǎn)換有不好使了。
這時有兩個選擇:

1. @babel/polyfill
2. @babel/plugin-transform-runtime搭配@babel/runtime
npm install --save @babel/polyfill
npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime
polyfill

中文翻譯是墊片。
es2015里不僅只有新的語法,還有實例的擴展,比如String.prototype.includes,其實這里只是調(diào)用了String實例的一個方法,我們無論怎么語法轉(zhuǎn)換也沒有什么用吧,如果我們在不支持String.prototype.includes的編譯器里跑這些代碼,會得到 'foo'.includes is not a function. 這樣的一個報錯,而不是語法報錯。
Polyfill提供的就是一個這樣功能的補充,實現(xiàn)了Array、Object等上的新方法,實現(xiàn)了Promise、Symbol這樣的新Class等。到這里應(yīng)該能明白了,為什么安裝@babel/polyfill沒有-dev,因為就算代碼發(fā)布后,編譯后的代碼依然會依賴這些新特性來實現(xiàn)功能。
雖然@babel/polyfill提供了我們想要的所有新方法新類,但是這里依然存在一些問題:
1.體積太大:比如我只用了String的新特性,但是我把整個包都引進來了,這不是徒增了很多無用的代碼,解決這個問題可以采用按需加載,我們有env這個preset,它又一個useBuiltIns選項,如果設(shè)置成"usage",那么將會自動檢測語法幫你require你代碼中使用到的功能。

[
    "@babel/env",
    {
      targets: {
        edge: "17",
        firefox: "60",
        chrome: "67",
        safari: "11.1",
      },
      "useBuiltIns": "usage"
    },
  ]

2.污染全局環(huán)境:如果你引用了 @babel/polyfill,那么像Promise這樣的新類就是掛載在全局上的,這樣就會污染了全局命名空間??赡茉谝粋€團建建立的項目問題不太大,但是如果你是一個工具的開發(fā)者,你把全局環(huán)境污染了,別人用你的工具,就有可能把別人給坑了。解決這個問題就只能引入@babel/plugin-transform-runtime 搭配@babel/runtime來替代 @babel/polyfill

transform-runtime

主要功能:

  1. 避免多次編譯出helper函數(shù):
    Babel轉(zhuǎn)移后的代碼想要實現(xiàn)和原來代碼一樣的功能需要借助一些幫助函數(shù),比如:
class Person {}

會被轉(zhuǎn)換為:

"use strict";
function _classCallCheck(instance, Constructor) {
  if (!(instance instanceof Constructor)) {
    throw new TypeError("Cannot call a class as a function");
  }
}

var Person = function Person() {
  _classCallCheck(this, Person);
};

這里_classCallCheck就是一個helper函數(shù),試想下如果我們很多文件里都聲明了類,那么就會產(chǎn)生很多個這樣的helper函數(shù),積少成多增大了代碼體積。
這里的@babel/runtime包就聲明了所有需要用到的幫助函數(shù),而@babel/plugin-transform-runtime的作用就是將所有需要helper函數(shù)的文件,依賴@babel/runtime包:

"use strict";

var _classCallCheck2 = require("@babel/runtime/helpers/classCallCheck");

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ? obj : { default: obj };
}

var Person = function Person() {
  (0, _classCallCheck3.default)(this, Person);
};

這里就沒有再編譯出helper函數(shù)classCallCheck了,而是直接引用了@babel/runtime中的helpers/classCallCheck。

  1. 解決@babel/polyfill提供的類或者實例方法污染全局作用域的情況。
    @babel/plugin-transform-runtime會為代碼創(chuàng)建一個沙盒環(huán)境,為core-js這里內(nèi)建的實例提供假名,你可以無縫的使用這些新特性,而不需要使用require polyfill。

但是,記住,babel-runtime有個缺點,它不模擬實例方法,即babel-runtime沒有模擬內(nèi)置對象原型上的方法,所以類似Array.prototype.find這樣的方法,你通過babel-runtime是無法使用的。

用法.babelrc:

{
    "presets": [
        ["@babel/preset-env",{
            "targets": {
                "browsers": ["> 1%", "last 2 versions"]
            }
        }]
    ],
    "plugins": [
            [
                  "@babel/plugin-transform-runtime",
                  {
                    "corejs": false,
                    "helpers": true,
                    "regenerator": true,
                    "useESModules": false
                   }
            ]
    ]
}

貌似測試代碼只用了@babel/plugin-transform-runtime搭配@babel/runtime做測試時,竟然頁面可以用”foolish".includes("foo")這樣的方法,根本沒有引入polyfill,再次記錄一下。這似乎和上面的說法有點相悖。

參考2:https://github.com/creeperyang/blog/issues/25
參考3:https://github.com/kaivin/webpack4.x

2019-5-9找到的新資料,網(wǎng)絡(luò)上的資料比較亂,每個人的環(huán)境也不相同,一定要多做幾次測試代碼

useBuiltIns 和 transform-runtime 不能同時使用。


image.png
cnpm install core-js@3 --save

.babelrc
{
    // targets, useBuiltIns 等選項用于編譯出兼容目標環(huán)境的代碼
    // 其中 useBuiltIns 如果設(shè)為 "usage"
    // Babel 會根據(jù)實際代碼中使用的 ES6/ES7 代碼,以及與你指定的 targets,按需引入對應(yīng)的 polyfill
    // 而無需在代碼中直接引入 import '@babel/polyfill',避免輸出的包過大,同時又可以放心使用各種新語法特性。
    "presets": [
        ["@babel/preset-env",{
            "modules": false,
            "targets": {
                "browsers": ["> 1%", "last 2 versions"]
            },
            "useBuiltIns": "usage",
            "corejs": 3
        }],
        "@babel/preset-react"
    ],
    "plugins": [
        
    ]
}

3.uglifyjs-webpack-plugin

webpack4已經(jīng)不支持使用移除 webpack.optimize.UglifyJsPlugin 壓縮配置了, 推薦使用 optimization.minimize 屬性替代。

不需要install這個插件,相關(guān)代碼注釋,只用一行代碼minimize: true即可:

module.exports = merge(common, {
  mode: 'production',
  //devtool: 'source-map',
  optimization: {
    minimize: true, //取代 new UglifyJsPlugin(/* ... */)
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
...

4. postcss-loader 和 autoprefixer

npm install --save-dev postcss-loader autoprefixer

#webpack.common.js

module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              hmr: process.env.NODE_ENV === 'development',
            },
          },
          'css-loader', 
          {
            loader:'postcss-loader',
            options: {
              plugins: [
                require("autoprefixer")({
                  //必須設(shè)置支持的瀏覽器才會自動添加添加瀏覽器兼容
                  browsers : ['last 10 versions']
                })
              ]
            }
          }
          /*,
          'postcss-loader',
          'sass-loader',*/
        ]
      }
    ]
  }

https://github.com/browserslist/browserslist#queries

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄第1章 webpack簡介 11.1 webpack是什么? 11.2 官網(wǎng)地址 21.3 為什么使用 web...
    lemonzoey閱讀 1,828評論 0 1
  • 版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 webpack介紹和使用 一、webpack介紹 1、由來 ...
    it筱竹閱讀 11,458評論 0 21
  • 一、webpack和npm的關(guān)系 npm是包管理器,及可以執(zhí)行命令包(webpack可以看成是功能強大的命令包,除...
    js_hcl閱讀 1,679評論 1 3
  • webpack4 的使用文件夾名稱不要用中文, 不要有 webpack 關(guān)鍵字. 全局安裝 初始化? 局部安裝(為...
    wudimingwo閱讀 676評論 0 0
  • 現(xiàn)在,讓我們懷著愉悅而放松的心情為今天的好種子澆水施肥曬太陽。 我近期最想實現(xiàn)的一個愿望或目標是:1.氧氣般金錢收...
    冰山軒兒閱讀 292評論 0 1

友情鏈接更多精彩內(nèi)容