This project, inspired by Phil Walton's articleDeploying es2015 Code in Production Today,adds tooling to simplify the additional configuration with aWebpack plugin, BabelMultiTargetPlugin
.
Using the plugin requires making a few small changes to your existing webpack configuration:
Replace any instances of 'babel-loader'
with BabelMultiTargetPlugin.loader()
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.
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 exclude
property of any rules using BabelMultiTargetPlugin.loader()
TypeScript
BabelMultiTargetPlugin.loader()
after your compiler loader (remember, loaders are run bottom to top)tsconfig
to target
es6 or higherVue
'vue-loader'
with BabelMultiTargetPlugin.loader('vue-loader')
expose-loader
expose-loader
must be defined before rules using BabelMultiTargetPlugin.loader()
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
.BabelMultiTargetPlugin.loader
to BabelMultiTargetPlugin.loader()
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.
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">
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.
{ modules: false, useBuiltIns: 'usage' }
modules
is forced to false
to avoid problems with transformed commonjs modulesdoNotTarget
(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>
tagsafari10NoModuleFix.inject
('head'
| 'body'
) - element to inject the script tag into (HtmlWebpackPlugin
only)
'head'
'body'
the tag will be inserted before other script tags.safari10NoModuleFix.minify
(boolean
) - minify the fix (uses terser with default settings)
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).
// 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(),
],
};
// 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(),
],
};
// 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,
},
},
}),
],
};
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/,
],
});
Several simple use cases are provided to show how the plugin works.
# installs dependencies for all example projects; requires bash and yarn
yarn setup
# builds all example projects
yarn examples
# build just the specified example projects
yarn es6-plain typescript-plain
# 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
.
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.
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.
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.
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)
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.
The output generated by this plugin is tested on the following browsers courtesy of BrowserStack:
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