Loading JavaScript(加载Javascript)
Webpack processes ES2015 module definitions by default and transforms them into code. It does not transform specific syntax, such as const
, though. The resulting code can be problematic especially in the older browsers.
Webpack默认情况下处理ES015模块定义并转换成代码。但它 不能 转换特殊语法, 如const
。生成的代码可能会有问题,尤其是对于传统浏览器。
To get a better idea of the default transform, consider the example output below (npm run build -- --devtool false --mode development
):
为了更好的理解默认转换,参考下面示例的输出(npm run build -- --devtool false --mode development
):
dist/main.js
...
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = ((text = "Hello world") => {
const element = document.createElement("div");
element.className = "pure-button";
element.innerHTML = text;
return element;
});
...
The problem can be worked around by processing the code through Babel, a famous JavaScript compiler that supports ES2015+ features and more. It resembles ESLint in that it's built on top of presets and plugins. Presets are collections of plugins, and you can define your own as well.<br/>
用Babel来处理代码可以绕过这个问题, 它是一个知名的Javascript编译器,支持ES015+特性和其他一些功能. 它与ESLint类似,也是在预设(presets)和插件之上构建。预设(Presets)是插件的集合,你也可以自己定义<br/>
T> Given sometimes extending existing presets is not enough, modify-babel-preset allows you to go a step further and configure the base preset in a more flexible way.<br/>
T> 鉴于有时扩展现有预设是不够的, modify-babel-preset 让你能更进一步并以更灵活的方式配置基本预设。
Using Babel with Webpack Configuration(使用babel与webpack配置)
Even though Babel can be used standalone, as you can see in the SurviveJS - Maintenance book, you can hook it up with webpack as well. During development, it can make sense to skip processing if you are using language features supported by your browser.<br/>
即使Babel可以单独使用,正如你在 SurvieJS-Maintenance书中所看到的,你也可以把它和Webpack连接起来。在开发的时候,如果你的浏览器支持语言特性,跳过这步处理还是不错的。
Skipping processing is a good option primarily if you don't rely on any custom language features and work using a modern browser. Processing through Babel becomes almost a necessity when you compile your code for production, though.<br/>
如果不依赖特定的语言特性并工作在现代浏览器上,跳过处理是一个不错的选择。但是当你为生产环境编译代码时,通过Babel处理源码几乎是一个必选项。
You can use Babel with webpack through babel-loader. It can pick up project level Babel configuration, or you can configure it at the webpack loader itself. babel-webpack-plugin is another lesser-known option.<br/>
你可以通过babel-loader在Webpack中使用Babel。它可以使用项目级别的配置,或者在Webpack的加载器中配置它。babel-webpack-plugin 是另一个相对不太知名的选择。
Connecting Babel with a project allows you to process webpack configuration through it. To achieve this, name your webpack configuration using the webpack.config.babel.js convention. interpret package enables this, and it supports other compilers as well.
将Babel与项目相连,就能通过它来处理Webpack配置了。要实现这个功能,根据约定用 webpack.config.babel.js 命名你的Webpack配置文件. interpret 包实现了这个功能,它还支持其他编译器。
T> Given that Node supports the ES2015 specification well these days, you can use a lot of ES2015 features without having to process configuration through Babel.<br/>
T> 考虑到近来 Node supports the ES2015 specification well , 你可以直接使用很多ES2015的特性而不必通过Babel来处理配置了。
W> If you use webpack.config.babel.js, take care with the "modules": false,
setting. If you want to use ES2015 modules, you could skip the setting in your global Babel configuration and then configure it per environment as discussed below.
W> 如果使用webpack.config.babel.js, 请注意配置项"modules": false,
. 如果想使用ES017的模块特性,可以跳过Babel的全局配置,然后像下面那样根据不同环境的需要单独配置。
{pagebreak}
Setting Up babel-loader(设置 babel-loader)
The first step towards configuring Babel to work with webpack is to set up babel-loader. It takes the code and turns it into a format older browsers can understand. Install babel-loader and include its peer dependency @babel/core:
让Babel和Webpack连携工作的第一步是配置babel-loader。它将代码转换成传统浏览器能够识别的格式。安装 babel-loader 以及它的同侪依赖(peer dependency) @babel/core。
npm install babel-loader @babel/core --save-dev
As usual, let's define a function for Babel:
和往常一样,我们为Babel定义一个函数:
webpack.parts.js
exports.loadJavaScript = ({ include, exclude } = {}) => ({
module: {
rules: [
{
test: /\.js$/,
include,
exclude,
use: "babel-loader",
},
],
},
});
Next, you need to connect this to the main configuration. If you are using a modern browser for development, you can consider processing only the production code through Babel. It's used for both production and development environments in this case. Also, only application code is processed through Babel.<br/>
下面,你需要把这个函数与主配置联接。如果在使用现代浏览器开发,可以只有在处理生产环境代码时使用Babel。在这个例子中,生产环境和开发环境同时使用了Babel。并且,只有应用代码才通过Babel处理。
{pagebreak}
Adjust as below:
如下调整:
webpack.config.js
const commonConfig = merge([
...
leanpub-start-insert
parts.loadJavaScript({ include: PATHS.app }),
leanpub-end-insert
]);
Even though you have Babel installed and set up, you are still missing one bit: Babel configuration. The configuration can be set up using a .babelrc dotfile as then other tooling can use the same.
即使安装了Babel,并进行了配置,还是差了一点:Babel的配置。可以使用 .babelrc 点文件设置配置,其他工具也可以使用相同的点文件。
W> If you try to import files outside of your configuration root directory and then process them through babel-loader, this fails. It's a known issue, and there are workarounds including maintaining .babelrc at a higher level in the project and resolving against Babel presets through require.resolve
at webpack configuration.
W> 如果从配置的根目录 以外 的地方导入文件这会导致 babel-loader 处理失败。这是一个已和的问题 a known issue, 不过有其他的方法来解决,包括在项目中把 .babelrc 级别设置得更高并通过Webpack配置中的 require.resolve
对Babel的预设进行处理。
Setting Up .babelrc (设置 .babelrc)
At a minimum, you need babel-preset-env. It's a Babel preset that enables the required plugins based on the optional environment definition you pass to it.<br/>
你最少需要 babel-preset-env。 它是一个Babel预设,根据传递给它的可选环境定义启用所需的插件。
Install the preset first:
首先安装预设:
npm install @babel/preset-env --save-dev
To make Babel aware of the preset, you need to write a .babelrc. Given webpack supports ES2015 modules out of the box, you can tell Babel to skip processing them. Jumping over this step would break webpack's HMR mechanism although the production build would still work. You can also constrain the build output to work only in recent versions of Chrome.
创建一个 .babelrc 来让它注意到预设。 假设Webpack直接支持ES2015 模块特性(Module),可以让Babel直接跳过处理他们。尽管生产环境构建还会工作,但是跳过这一步会破坏Webpack的HMR机制。您还可以限制构建输出只能在最新版本的Chrome中工作。
Adjust the target definition as you like. As long as you follow browserslist, it should work. Here's a sample configuration:
如果愿意的话可以调整目标定义。只要按照browserslist,应该能够工作。下面是一个配置的示例:
.babelrc
{
"presets": [
[
"@babel/preset-env",
{
"modules": false,
}
]
]
}
If you execute npm run build -- --devtool false --mode development
now and examine dist/main.js, you will see something different based on your .browserslistrc
file.
如果你现在执行 npm run build -- --devtool false --mode development
并检查 dist/main.js, 基于 .browserslistrc
文件这里发生了一些改变.
{pagebreak}
Try to include only a definition like IE 8
there, and the code should change accordingly:
试着在里面仅包含一个定义如 IE 8
,代码也发生了相应的改变:
dist/main.js
...
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony default export */ __webpack_exports__["default"] = (function () {
var text = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "Hello world";
var element = document.createElement("div");
element.className = "pure-button";
element.innerHTML = text;
return element;
});
...
Note especially how the function was transformed. You can try out different browser definitions and language features to see how the output changes based on the selection.
尤其要注意函数是如何发生改变的。您可以尝试不同的浏览器定义和语言特性,以查看输出是如何根据选择进行更改的。
Polyfilling Features("填坑"特性)
<翻译略,主要是针对传统浏览器的兼容问题>
babel-preset-env allows you to polyfill certain language features for older browsers. For this to work, you should enable its useBuiltIns
option ("useBuiltIns": true
) and install babel-polyfill. You have to include it in your project either through an import or an entry (app: ["babel-polyfill", PATHS.app]
). babel-preset-env rewrites the import based on your browser definition and loads only the polyfills that are needed.
babel-polyfill pollutes the global scope with objects like Promise
. Given this can be problematic for library authors, there's transform-runtime option. It can be enabled as a Babel plugin, and it avoids the problem of globals by rewriting the code in such way that they aren't be needed.
W> Certain webpack features, such as Code Splitting, write Promise
based code to webpack's bootstrap after webpack has processed loaders. The problem can be solved by applying a shim before your application code is executed. Example: entry: { app: ["core-js/es6/promise", PATHS.app] }
.
Babel Tips(Babel小窍门)
There are other possible .babelrc options beyond the ones covered here. Like ESLint, .babelrc supports JSON5 as its configuration format meaning you can include comments in your source, use single quoted strings, and so on.
除了介绍的选项,还有其他一些.babelrc options. 和ESLint一样, .babelrc 用JSON5 作为它的配置格式,这样就可以在代码中包含注释,使用单引号等等。
Sometimes you want to use experimental features that fit your project. Although you can find a lot of them within so-called stage presets, it's a good idea to enable them one by one and even organize them to a preset of their own unless you are working on a throwaway project. If you expect your project to live a long time, it's better to document the features you are using well.
有时要在项目中使用一些试验中的特性。尽管可以找到很多所谓的阶段性预设,但是最好还是一个一个地启用它们,甚至将它们组织成自己的预设,除非您正在处理一个一次性项目。如果想让你的项目活得长点儿,最好文档化你使用得比较好的特性。
Babel isn't the only option although it's the most popular one. Buble by Rich Harris is another compiler worth checking out. There's experimental buble-loader that allows you to use it with webpack. Buble doesn't support ES2015 modules, but that's not a problem as webpack provides that functionality.
Babel尽管深受欢迎但不是唯一选择。Rich Harris的Buble 是另一个值得一试的编译器。 有个试验用的加载器buble-loader
{pagebreak}
Babel Plugins(Babel插件)
Perhaps the greatest thing about Babel is that it's possible to extend with plugins:
或许Babel最伟大之处就在于它允许用插件扩展:
-
babel-plugin-import rewrites module imports so that you can use a form such as
import { Button } from "antd";
instead of pointing to the module through an exact path. -
babel-plugin-import 重写了模块导入,因此所以使用这样的格式:
import { Button } from "antd";
而不用明确的指定模块的路径。 - babel-plugin-import-asserts asserts that your imports have been defined.
- babel-plugin-import-asserts 断言那些已经被定义的导入.
- babel-plugin-jsdoc-to-assert converts JSDoc annotations to runnable assertions.
- babel-plugin-jsdoc-to-assert converts JSDoc annotations to runnable assertions.
- babel-plugin-jsdoc-to-assert 将 JSDoc 注释转换成可运行的断言。
-
babel-plugin-log-deprecated adds
console.warn
to functions that have@deprecate
annotation in their comment. -
babel-plugin-log-deprecated 为那些在注释中添加了
@deprecate
标志的函数添加console.warn
. -
babel-plugin-annotate-console-log annotates
console.log
calls with information about invocation context, so it's easier to see where they logged. -
babel-plugin-annotate-console-log 将调用上下文添加到
console.log
的调用注释中 , 这样就能很容易得找到在哪里被调用的了. - babel-plugin-sitrep logs all assignments of a function and prints them.
- babel-plugin-sitrep 记录所有的函数赋值并将他们打印出来.
- babel-plugin-webpack-loaders allows you to use certain webpack loaders through Babel.
- babel-plugin-webpack-loaders 让你能通过Babel使用特定的Webpack加载器.
- babel-plugin-syntax-trailing-function-commas adds trailing comma support for functions.
- babel-plugin-syntax-trailing-function-commas 为函数添加逗号支持。
-
babel-plugin-transform-react-remove-prop-types allows you to remove
propType
related code from your production build. It also allows component authors to generate code that's wrapped so that setting environment atDefinePlugin
can kick in as discussed in the book. -
babel-plugin-transform-react-remove-prop-types 帮你在生产环境编译中把
propType
相关的代码删除掉. 它还允许组件作者生成封装的代码,以便在' DefinePlugin '设置环境,如书中讨论的那样。
T> It's possible to connect Babel with Node through babel-register or babel-cli. These packages can be handy if you want to execute your code through Babel without using webpack.
T> 可以通过babel-register 或 babel-cli 来连接 Babel和 Node。如果你想只通过Babel而不用Webpack来执行你的代码,这些包会非常方便。
Enabling Presets and Plugins per Environment(根据环境打开预设和插件)
Babel allows you to control which presets and plugins are used per environment through its env option. You can manage Babel's behavior per build target this way.
通过env option, Babel让你能够根据环境控制哪些预设和插件可用. 可以根据构建目标的不同来管理Babel的行为.
env
checks both NODE_ENV
and BABEL_ENV
and adds functionality to your build based on that. If BABEL_ENV
is set, it overrides any possible NODE_ENV
.env
会同时检查 NODE_ENV
和 BABEL_ENV
并基于此向你的构建中添加功能。 如果 BABEL_ENV
被设置, 它将覆盖所有可能的 NODE_ENV
.
Consider the example below:
参考下面的例子:
.babelrc
{
...
"env": {
"development": {
"plugins": [
"annotate-console-log"
]
}
}
}
Any shared presets and plugins are available to all targets still. env
allows you to specialize your Babel configuration further.
任何共享的预设和插件对目标仍然可用。env
让你进一步定制你的Babel配置。
{pagebreak}
It's possible to pass the webpack environment to Babel with a tweak:
通过微调,可以将webpack环境传递给Babel:
webpack.config.js
module.exports = mode => {
leanpub-start-insert
process.env.BABEL_ENV = mode;
leanpub-end-insert
...
};
T> The way env
works is subtle. Consider logging env
and make sure it matches your Babel configuration or otherwise the functionality you expect is not applied to your build.
T> env
运行方式比较微妙. 考虑将env
记录到日志中,以确保它与你的Babel配置相匹配,否则你所期望的功能可能不会应用到构建上 .
Setting Up TypeScript(配置Typescript)
Microsoft's TypeScript is a compiled language that follows a similar setup as Babel. The neat thing is that in addition to JavaScript, it can emit type definitions. A good editor can pick those up and provide enhanced editing experience. Stronger typing is valuable for development as it becomes easier to state your type contracts.
微软的 TypeScript 是一种编译语言,它的配置方式与Babel类似。 除了兼容Javascript之外,它还可以使用类型定义。一个好的编辑器除了可以使用这些特性还能增强编写体验。更强的类型对于开发很有价值,因为它更容易声明类型契约。
Compared to Facebook's type checker Flow, TypeScript is a more secure option. As a result, you find more premade type definitions for it, and overall, the quality of support should be better.
与Facebook的类型检查程序流相比,TypeScript是一个更安全的选择。因此,您会发现它有更多预先定义的类型,总的来说,支持的质量应该更好。
You can use TypeScript with webpack using the following loaders:
可以通过下面的加载器在Webpack中使用Typescript:
T> There's a TypeScript parser for ESLint. It's also possible to lint it through tslint.
T> 有一个 TypeScript parser for ESLint. 也可以通过 tslint对其进行处理.
Setting Up Flow(配置流程)
Flow performs static analysis based on your code and its type annotations. You have to install it as a separate tool and then run it against your code. There's flow-status-webpack-plugin that allows you to run it through webpack during development.
Flow 基于代码和类型注释进行静态分析. 你不得不把它安装为一个独立的工具并在你的代码上运行它。有一个 flow-status-webpack-plugin 包可以让你在开发时通过Webpack执行它.
If you use React, the React specific Babel preset does most of the work through babel-plugin-syntax-flow. It can strip Flow annotations and convert your code into a format that is possible to transpile further.
如果在使用React, 通过包 babel-plugin-syntax-flow, Webpack特定的Babel预设完成了大部分工作。它可以剥离流注释,并将代码转换为可以进一步转换的格式。
There's also babel-plugin-typecheck that allows you to perform runtime checks based on your Flow annotations. flow-runtime goes a notch further and provides more functionality. These approaches complement Flow static checker and allow you to catch even more issues.
还有一个包 babel-plugin-typecheck 可以基于流注释进行运行时检查. flow-runtime 更进一步,提供了更多的功能。这些方法补充了流静态检查器,并允许您捕获更多的问题。
T> flow-coverage-report shows how much of your code is covered by Flow type annotations.
T> flow-coverage-report 显示流类型注释覆盖了多少代码。
{pagebreak}
Conclusion
Babel has become an indispensable tool for developers given it bridges the standard with older browsers. Even if you targeted modern browsers, transforming through Babel is an option.
Babel已经成为开发人员不可或缺的工具,因为它连接了标准与旧浏览器。即使是针对现代浏览器,通过Babel进行转换也是一种选择。
To recap:(总结)
- Babel gives you control over what browsers to support. It can compile ES2015+ features to a form the older browser understand. babel-preset-env is valuable as it can choose which features to compile and which polyfills to enable based on your browser definition.
- Babel 帮你能控制支持什么浏览器。它可以把ES2015+的特性编译成传统浏览器可以识别的格式。 babel-preset-env 是有价值的,因为它能基于浏览器判断哪个功能需要编译,哪个功能需要用Poyfill来帮助浏览器实现功能。
- Babel allows you to use experimental language features. You can find numerous plugins that improve development experience and the production build through optimizations.
- Babel 让你能使用试验中的语言特性。你可以找到大量的插件通过优化来改善开发体验和生产环境构建。
- Babel functionality can be enabled per development target. This way you can be sure you are using the correct plugins at the right place.
- 每个开发目标都可以启用Babel功能。这样可以确保在正确的地方使用了正确的插件。
- Besides Babel, webpack supports other solutions like TypeScript or Flow. Flow can complement Babel while TypeScript represents an entire language compiling to JavaScript.
- 除了Babel,webpack还支持其他的解决方案,如:TypeScript和Flow。Flow可以补充Babel,而TypeScript则代表了编译成JavaScript的别一种语言。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。