webpack-babel-multi-target-plugin

授权协议 Readme
开发语言 JavaScript
所属分类 Web应用开发、 常用JavaScript包
软件类型 开源软件
地区 不详
投 递 者 朱锐
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

webpack-babel-multi-target-plugin

This project, inspired by Phil Walton's articleDeploying es2015 Code in Production Today,adds tooling to simplify the additional configuration with aWebpack plugin, BabelMultiTargetPlugin.

Setup and Configuration

NPM

Using the plugin requires making a few small changes to your existing webpack configuration:

  • Replace any instances of 'babel-loader' with BabelMultiTargetPlugin.loader()

    • Do not use a Loader configuration object here - see Options Referencebelow for information on customizing options for 'babel-loader'
  • Add a loader rule for .js files if there isn't one already:

{
  test: /\.js$/,
  use: [
    BabelMultiTargetPlugin.loader(),
  ],
},

Note: The above example intentionally does not exclude node_modules.

  • Set resolve.mainFields to favor modern ES modules, which allows webpack to load the most modern source possible.There are several intersecting de-facto standards flying around, so this should cover as much as possible:
mainFields: [

  // rxjs and Angular Package Format
  // these are generally shipped as a higher ES language level than `module`
  'es2015',
  'esm2015',
  'fesm2015',

  // current leading de-facto standard - see https://github.com/rollup/rollup/wiki/pkg.module
  'module',

  // previous de-facto standard, superceded by `module`, but still in use by some packages
  'jsnext:main',

  // Angular Package Format - lower ES level
  'esm5',
  'fesm5',

  // standard package.json fields
  'browser',
  'main',
],
  • Add an instance of BabelMultiTargetPlugin to the webpackconfiguration's plugins property

  • BabelMultiTargetPlugin does not require any configuration - but canbe customized (see Options Reference below)

  • Remove any .babelrc - see Options Reference below for setting preset options

  • Remove any references to babel-loader from your package.json - it is a direct dependency ofwebpack-babel-multi-target-plugin, and may cause unexpected issues if there are duplicate instances due toa version mismatch

  • Remove any path or pattern matching node_modules from the excludeproperty of any rules using BabelMultiTargetPlugin.loader()

  • TypeScript

    • Loader rules must use BabelMultiTargetPlugin.loader() after your compiler loader (remember, loaders are run bottom to top)
    • Set tsconfig to target es6 or higher
  • Vue

    • Replace 'vue-loader' with BabelMultiTargetPlugin.loader('vue-loader')
  • expose-loader

    • Rules using expose-loader must be defined before rules using BabelMultiTargetPlugin.loader()
    • Do not import/require libraries exposed with expose-loader - either reference them from the global scope,or do not use expose-loader. You may also need to use Webpack's ProvidePlugin.

Upgrading from v1.x

  • Change usages of BabelMultiTargetPlugin.loader to BabelMultiTargetPlugin.loader()

Usage with ES6 Dynamic Imports

When using ES6's import(...) syntax, you may use Webpack's built-in chunk naming syntax to control the namingof the resulting chunk:

import(/* webpackChunkName: "my-dynamic-import" */'./some-other-module')

When working with imports that use an expression within the import syntax, BabelMultiTargetPlugin adds the [resource]tag to allow better control over the naming of the resulting chunk. The [resource] tag will be replaced by therelative path of the imported module, minus the file extension.

/*
 * ./src/
 *   - plugins
 *     - a
 *       plugin.js
*      - b
*        plugin.js
 *  
 */

// ./src/loader.js
import(/* webpackChunkName: "[resource]" */`./plugins/${plugin}/plugin.js`)

In the above example, the resulting chunks for the plugin files would be (depending on the target configuration):

  • a-plugin.js (legacy bundle for ./src/plugins/a/plugin.js)
  • a-plugin.modern.js (modern bundle for ./src/plugins/a/plugin.js)
  • b-plugin.js (legacy bundle for ./src/plugins/b/plugin.js)
  • b-plugin.modern.js (modern bundle for ./src/plugins/b/plugin.js)
// webpack.config.js

const BabelMultiTargetPlugin = require('webpack-babel-multi-target-plugin').BabelMultiTargetPlugin
const NamedLazyChunksPlugin =  require('webpack-babel-multi-target-plugin').NamedLazyChunksPlugin

module.exports = {
  ...
  
  plugins: [
    new BabelMultiTargetPlugin(),
    new NamedLazyChunksPlugin(),
  ],
}

NamedLazyChunkPlugin can also be used with plain ES6 Dynamic Imports as an alternative to Webpack's chunk namingsyntax.

Configuration Defaults

BabelMultiTargetPlugin does not require any options to be set. Thedefault behavior is:

  • Generate "modern" and "legacy" bundles.

  • The "modern" bundle assets will have their filenames appended with.modern, while the "legacy" bundle assets will remain the same. Thisenables these assets to be deployed without breaking anything since itwill still have the required polyfills.

  • "modern" browsers are the last 2 versions of each browser, excludingversions that don't support <script type="module">

Options Reference

  • babel.plugins (string[]) - a list of Babel plugins to use. @babel/plugin-syntax-dynamic-import is included automatically.

  • babel.presets (string[]) - a list of Babel presets to use. @babel/preset-env is included automatically.

  • babel.presetOptions (BabelPresetOptions) - options passed to @babel/preset-env. See Babel's preset-env options documentation for more info.

    • Default: { modules: false, useBuiltIns: 'usage' }
    • IMPORTANT: modules is forced to false to avoid problems with transformed commonjs modules
  • doNotTarget (RegExp[]) - an array of RegExp patterns for modules whichwill be excluded from targeting (see How It Works below)

  • exclude (RegExp[]) - an array of RegExp patterns for modules which willbe excluded from transpiling

  • targets ({ [browserProfile: string]: BabelTargetOptions }) - amap of browser profiles to target definitions. This is used to controlthe transpilation for each browser target. See Configuration Defaultsabove for default values.

    • targets[browserProfile].key (string) - Used internally toidentify the target, and is appended to the filename of an asset iftagAssetsWithKey is set to true. Defaults to browserProfile ifnot set.
    • targets[browserProfile].tagAssetsWithKey (boolean) - Determines whether thekey is appended to the filename of the target's assets. Defaults totrue for the "modern" target, and false for the "legacy" target.Only one target can have this property set to false.
    • targets[browserProfile].browsers Defines thebrowserslist usedby @babel/preset-env for this target.
    • targets[browserProfile].esModule (boolean) - Determines whetherthis target can be referenced by a <script type="module"> tag. Onlyone target may have this property set to true.
    • targets[browserProfile].noModule (boolean) - Determines whetherthis target can be referenced by a <script nomodule> tag. Onlyone target may have this property set to true.
    • targets[browserProfile].additionalModules (string[]) - An optionalarray of modules that will be prepended to the entry module for the target.
  • safari10NoModuleFix | safari10NoModuleFix.mode (boolean | 'external', 'inline' | 'inline-data' | 'inline-data-base64' ) - Embeds a polyfill/workaroundto allow the nomodule attribute to function correctly in Safari 10.1.See #9 for more information.

    • false - disabled (default)
    • true | 'inline' - adds the nomodule fix in an inline script (HtmlWebpackPlugin only)
    • 'inline-data' - adds the nomodule fix using a script tag with a data url (HtmlWebpackPlugin only)
    • 'inline-data-base64' - adds the nomodule fix using a script tag with a base64-encoded data url (HtmlWebpackPlugin only)
    • 'external' - adds the nomodule fix as a separate file linked with a <script src> tag
  • safari10NoModuleFix.inject ('head' | 'body') - element to inject the script tag into (HtmlWebpackPlugin only)

    • Default: 'head'
    • When using 'body' the tag will be inserted before other script tags.
  • safari10NoModuleFix.minify (boolean) - minify the fix (uses terser with default settings)

    • Default: false (to maintain compatibility with older versions of the plugin without this option)
  • normalizeModuleIds: (boolean) - EXPERIMENTAL. Removes the babel targeting query from module ids so theyuse what the module id would be without using BabelMultiTargetPlugin, and adds a check to webpack's bootstrappingcode that stops bundle code from executing if it detects that webpack has already been bootstrapped elsewhere.This has the effect of preventing duplicate modules from loading in instances where the browser loads both bundles(e.g. Safari 10.1).

Configuration Examples

Basic Usage

// webpack.config.js

const BabelMultiTargetPlugin = require('webpack-babel-multi-target-plugin').BabelMultiTargetPlugin;

module.exports = {

    entry: 'src/main.js',

    resolve: {
        mainFields: [
            'es2015',
            'module',
            'main',
        ],
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    BabelMultiTargetPlugin.loader(),
                ],
            },
        ],
    },

    plugins: [
        new BabelMultiTargetPlugin(),
    ],

};

TypeScript

// webpack.config.js

const BabelMultiTargetPlugin = require('webpack-babel-multi-target-plugin').BabelMultiTargetPlugin;

module.exports = {

    entry: 'src/main.ts',

    resolve: {
        mainFields: [
            'es2015',
            'module',
            'main',
        ],
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    BabelMultiTargetPlugin.loader(),
                ],
            },
            {
                test: /\.ts$/,
                use: [
                    BabelMultiTargetPlugin.loader(),
                    'ts-loader'
                ],
                options: {
                    useCache: true,
                    cacheDirectory: 'node_modules/.cache/ts-loader',
                },
            },
        ],
    },

    plugins: [
        new BabelMultiTargetPlugin(),
    ],

};

With Options

// webpack.config.js

const BabelMultiTargetPlugin = require('webpack-babel-multi-target-plugin').BabelMultiTargetPlugin;

module.exports = {

    entry: 'src/main.js',

    resolve: {
        mainFields: [
            'es2015',
            'module',
            'main',
        ],
    },

    module: {
        rules: [
            {
                test: /\.js$/,
                use: [
                    BabelMultiTargetPlugin.loader(),
                ],
            },
        ],
    },

    plugins: [
        new BabelMultiTargetPlugin({

            babel: {
                // babel preset-env plugin options go here
            },

            // excludes the untargetable-library module from being targeted
            doNotTarget: [
                /node_modules\/untargetable-library/,
            ],

            // excludes the transpiling-trouble module from being transpiled
            exclude: [
                /node_modules\/transpiling-trouble/
            ],

            // swap which target gets the name appended
            targets: {

                // results in the "modern" bundle being output as main.js
                // the default is main.modern.js
                modern: {
                    tagAssetsWithKey: false,
                },

                // results in the "legacy" bundle being output as main.old-and-broke.js
                // the default is main.js
                legacy: {
                    key: 'old-and-broke',
                    tagAssetsWithKey: true,
                },
            },
        }),
    ],

};

Don't Transpile ES5-only Libraries

Some libraries may cause runtime errors if they are transpiled - often,they will already have been transpiled by Babel as part of the author'spublishing process. These errors may look like:

Cannot assign to read only property 'exports' of object '\#\<Object\>'

or

__webpack_require__(...) is not a function

These libraries most likely need to be excluded from Babel'stranspilation. While the plugin will automatically attempt to filter outCommonJs modules, you can also specify libraries to be excluded in theBabelMultiTargetPlugin constructor:

new BabelMultiTargetPlugin({
    exclude: [
        /node_modules\/some-es5-library/,
        /node_modules\/another-es5-library/,
    ],
});

Example Projects

Several simple use cases are provided to show how the plugin works.

Install Example Project Dependencies

# installs dependencies for all example projects; requires bash and yarn
yarn setup

Build the Example Projects

# builds all example projects
yarn examples

# build just the specified example projects
yarn es6-plain typescript-plain

Example Project Dev Server

# builds and serves all example projects
yarn start

# builds and serves just the specified example projects
yarn start es6-plain typescript-plain

Note that when running all example projects concurrently, you may need to increaseNode's memory limit:

NODE_OPTIONS="--max-old-space-size=8192" yarn start

Examples will be available at http://HOST:PORT/examples/EXAMPLE_NAME.

How It Works

This plugin works by effectively duplicating each entry point, and giving ita target. Each target corresponds to a browser definition that is passedto Babel. As the compilation processes each entry point, the target filtersdown from the entry point through each of its dependencies. Once thecompilation is complete, any CSS outputs are merged into a singlemodule so they are not duplicated (since CSS will be the same regardlessof ES supported level). If HtmlWebpackPluginis being used, the script tags are updated to use the appropriatetype="module" and nomodule attributes.

Transpiling node_modules

In order to have the greatest possible positive effect, the compilation mustbe able to start with the high possible ES level of source code. This is whythe extra entries were added to the mainFields array, and whynode_modules is not excluded from loader rules. This ensures that evendependencies can take advantage of being able to be bundled with ES6features and syntax, and the more verbose syntax and polyfill-ladenonly included for legacy browsers.

Blind Targeting

In some circumstances, such as lazy-loaded routes and modules withAngular, Vue, and ES6 dynamic imports, it may not be possible todetermine the entry point of a module. In these cases, the plugin willassign the module a target on its own. It does this by creating an arrayof the targets, and removing and assigning one target each time itencounters a given resource.

If you encounter a BlindTargetingError while attempting to use thisplugin, please create an issue with a simple reproduction.

Benefits

  • Automatically sets up your index HTML files with both "modern" and"legacy" bundles

  • Uses ES2015 source when available, and attempts to automatically avoidre-transpiling ES5/CommonJs code

  • Avoid using between 30-70 KB of polyfill code on browsers that don'tneed them (depends on project size and features used)

Caveats

  • Increased build time - since the plugin duplicates entry points, everythinghas to be done twice. This can be helped with appropriate cacheconfigurations where they are available (Babel, TypeScript, etc), butit may make sense to avoid using this plugin during development.

  • May not play nice with hard-source-webpack-plugin

  • Code Splitting - Since CommonJs dependencies can be shared between"modern" and "legacy" bundles, apps with multiple entries orlazy-loaded modules may end up with a large number of "vendor" chunks.

Testing

The output generated by this plugin is tested on the following browsers courtesy of BrowserStack:

  • Chrome
  • Firefox
  • Edge
  • Safari (including 10.1 on Mac OS and 10.3 on iOS)
  • IE 11

  • webpack4 loader 通过loader加载任何类型的资源 文件资源加载器 file-loader 大文件(大于10kb)单独提取存放,提高加载速度 npm i file-loader yarn add file-loader { ​ text:/.png$/ ​ use:‘file-loader’ } url-loader 需要用的话,首先需要先安装file-loader 可以将文件转换

  • Webpack学习-深入浅出 简介 webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具 Webpack是提升前端生产力的利器 个人觉得 Webpack 应该是现代化前端开发的基石,也是目前前端生产力的代名词。 Webpack 与模块化开发 随着前端应用的日益复杂化,我们的项目已经逐渐膨胀到了不得不花大量时间去管理的程度。而模块化就是一种最主流的项目组织方式,它通过把复

  • webpack5 近期终于有时间和精力专注于公司技术基础建设了,于是一开始,将公司的Saas系统改造成了微前端模式,解决了历史遗留的一部分问题 接着,想着webpack5已经发布这么久了,该在生产环境用起来了,也顺势想推动微前端、webpack5、vite在业内的普及率,没看过我之前文章的朋友可以在文末找找,干货真的很多 正式开始 webpack5升级后,有哪些改变? 通过持久化缓存提高性能 采用

  • 概述 本质 JavaScript 应用程序的静态模块打包器 核心 加载器(Loader)机制 工作流程 配置初始化 webpack 会首先读取配置文件,执行默认配置 编译前准备 webpack 会实例化 compiler,注册 plugins、resolverFactory、hooks。 reslove 前准备 webpack 实例化 compilation、NormalModuleFactory

  • 前端模块化开发-Webpack(笔记) 小技巧:折起代码,command+k+0 加载器loader webpack,是一个打包儿的工具,具体的某项功能一般通过不同类型的加载器,或者插件实现,一般分为这几类: 编译转换类; 文件操作类; 代码检查类 分割 提示:babel只是一个转换新特性的工具集合,具体使用还要指定插件 webpack加载资源的方式,以下都支持: 遵循 ES Modules

  • 由于 webpack5 需要 node 版本>= 10.13.0,请先将 node版本 升级, npm版本 用node自带的就可以了。 官方最新的node版本好像不兼容下面的webpack5配置,建议升级成 LTS版本 ,这里我升级的是v14.18.1的LTS版本,可以完美兼容。 配置代码我怕各种不兼容你们拿去不能用,索性全部贴出来,用到什么参考下我的版本,这些版本间的兼容性一言难尽,不要问我为什

 相关资料
  • 专为微信小程序做的 webpack 的 构建目标(Targets)。 如果你不了解什么是 webpack, 可以查看 webpack文档 。 如果不了解什么又是 target,可以查看文档 构建目标(Targets)。 实现的功能 修改自 webpack/lib/JsonpTemplatePlugin.js 中关于 target 为 web 部分的源码。 主要兼容微信小程序中的全局变量。例如把 w

  • babel-plugin-webpack-alias This Babel 6 plugin allows you to use webpack aliases and most of webpack resolve features in Babel. This plugin is simply going to take the aliases defined in your webpack

  • DEPREACTED due to lack of support/bug fixes/ new features, project abandoned, please migrate on https://github.com/webpack-contrib/terser-webpack-plugin Babel Minify Webpack Plugin A Webpack Plugin fo

  • koa-babel-webpack-boilerplate A simple boilerplate to create REST apps with koa@next (currently 2.0.0-alpha.3) babel (for async, await and stage-2 support) webpack How to use Boilerplate is packed wit

  • webpack-babel-env-deps Find dependencies to transpile with Babel. �� Read the docs! A webpack helper to find dependencies of your project that require transpilation with Babel (and @babel/preset-env)b

  • Tree-shaking example with Babel and Webpack This repository shows how to configure Babel and Webpack to enable tree-shaking.It will eliminate dead code if they have ES2015 module format. The source co