webpack编译打包 JS / TS

734 阅读2分钟

处理高级语法

es6

插件
  • babel-loader:

使用 Babel 和 webpack 转译 ES6 到 ES5

  • @babel/core

babel核心模块,调用transform转化方法实现转化

  • @babel/preset-env

转化目标模块(即ES5模块)

安装插件
$ yarn add babel-loader @babel/core @babel/preset-env -D
webpack配置

module.rules添加babel-loader配置

module: {
    rules: [
      {
        test: /\.js$/i,
        use: {
          {
            loader: 'babel-loader',
            options: {
              presets: [
                '@babel/preset-env', 
                {
                    "targets": {
                      "browsers": "last 2 versions"
                    },
                    "loose": true,
                    "modules": "commonjs",
                    "useBuiltIns": false
                }
              ],
              plugins: []
            },
          },
        },
        include: path.resolve(__dirname, 'src'),
        exclude: /(node_modules|bower_components)/,
      }
    ],
  }

然后 yarn build 打包,你会发现项目中的ES6语法全部被转化成了ES5语法

ES7装饰器 & Class语法解析

插件
  • @babel/plugin-proposal-decorators
  • @babel/plugin-proposal-class-properties
安装插件
$ yarn add @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators -D
webpack配置

plugins 中添加插件:

module: {
    rules: [
      {
        test: /\.js$/i,
        use: {
          {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-env'],
              plugins: [
                ["@babel/plugin-proposal-decorators", { "legacy": true }],
                ["@babel/plugin-proposal-class-properties", { "loose" : true }]
              ]
            },
          },
        },
        include: path.resolve(__dirname, 'src'),
        exclude: /(node_modules|bower_components)/,
      }
    ],
  }

也可以把 babel 配置单独配置到.babelrc文件中:

{
  "presets": [
    "@babel/preset-env",
    {
        "targets": {
            "browsers": "last 2 versions"
        },
        "loose": true,
        "modules": "commonjs",
        "useBuiltIns": false
    }
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ]
  ]
}
@babel/plugin-transform-runtime

babel在处理类似于Array的includes,from等高阶语法时,需要polyfill解析编译

使用@babel/plugin-transform-runtime插件的理由:

  1. @babel/preset-env设置useBuiltIns:"entry"时,需要手动引入polyfill,设置useBuiltIns:"usage"时,polyfill作为全局对象引入,容易造成全局变量污染。@babel/plugin-transform-runtime可以对polyfill做到按需引入。
  2. babel在编译js时会使用很多辅助代码。如_extend,@babel/plugin-transform-runtime可以把这些辅助代码进行抽离,缩小文件大小

@babel/plugin-transform-runtime配置:

//.babelrc
{
  "presets": [
    "@babel/preset-env",
    {
        "targets": {
            "browsers": "last 2 versions"
        },
        "loose": true,
        "modules": "commonjs",
        "useBuiltIns": false
    }
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ],
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 3,
        "helpers": true
      }
    ]
  ]
}

编译React

安装babel react解析

$ yarn add @babel/preset-react

然后babel配置中添加react相关配置

//.babelrc
{
  "presets": [
    [
        "@babel/preset-env",
        {
            "targets": {
                "browsers": "last 2 versions"
            },
            "loose": true,
            "modules": "commonjs",
            "useBuiltIns": false
        }
    ],
    "@babel/preset-react"
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ],
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 3,
        "helpers": true
      }
    ]
  ]
}

编译TypeScript

安装babel typescript解析

$ yarn add @babel/preset-typescript -D

然后在babel添加typescript解析配置

//.babelrc
{
  "presets": [
    [
        "@babel/preset-env",
        {
            "targets": {
                "browsers": "last 2 versions"
            },
            "loose": true,
            "modules": "commonjs",
            "useBuiltIns": false
        }
    ],
    "@babel/preset-react",
    "@babel/preset-typescript"
  ],
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        "loose": true
      }
    ],
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 3,
        "helpers": true
      }
    ]
  ]
}

babel7以下版本可以选择typescript+ts-loader/awesome-typescript-loader方案

处理全局变量

expose-loader

允许暴露一个模块(整体或者部分)给全局对象(self、window 和 global)

$ yarn add expose-loader -D

下面以jquery为例,内联用法:

import $ from "expose-loader?exposes=$,jQuery!jquery";
//`jquery` 添加到全局对象中,其名称为 `$``jQuery`,多个名称之间用“,”隔开
//此时就可以使用window.$和window.jQuery

也可以写到webpack配置中:

module.exports = {
  module: {
    rules: [
      {
        test: require.resolve("jquery"),
        loader: "expose-loader",
        options: {
          exposes: ["$", "jQuery"],
        },
      },
      {
        test: require.resolve("underscore"),
        loader: "expose-loader",
        options: {
          exposes: [
            "_.map|map",
            {
              globalName: "_.reduce",
              moduleLocalName: "reduce",
            },
            {
              globalName: ["_", "filter"],
              moduleLocalName: "filter",
            },
          ],
        },
      },
    ],
  },
};

webpack.ProvidePlugin

自动向各模块注入内容,我们还是以jquery为例:

const webpack = require('webpack')
module.exports = {
  plugins: [
    new webpack.ProvidePlugin({
        $: 'jquery'
    })
  ]
}

此时webpack打包的时候,会往各模块自定注入“$”作为jquery的别名

webpack不打包第三方cdn引入模块

有时候我们在html中通过script引入的第三方cdn包,不希望被webpack打包,可以通过配置externals(从输出的 bundle 中排除依赖)实现

//index.html
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>

//webpack.config.js
module.exports = {
  //...
  externals: {
    jquery: 'jQuery',
  },
};

//js中依然可以这样使用
import $ from 'jquery';

$('.my-element').animate(/* ... */);