webpack生命周期详解(使用Babel和)
webpack生命周期详解(使用Babel和)用这个创建一个package.json文件:在您的计算机上的某个位置创建一个根文件夹,然后从您的终端/命令行导航到它。这将是您的<ROOT>文件夹。从下面的链接中可以看出,从 ES6 转换到 ES5 显着增加了我们可以支持的浏览器数量。构建系统的目的是使我们的代码为浏览器和生产环境做好准备所需的工作流程自动化。这可能包括诸如将代码转换为不同的标准、将 Sass 编译为 CSS、捆绑文件、压缩和压缩代码等步骤。为了确保这些是一致的可重复的,需要一个构建系统来从单个命令以已知顺序启动这些步骤。为了继续进行,您需要同时安装Node.js 和 npm(它们打包在一起)。我建议使用nvm 之类的版本管理器来管理您的 Node 安装(方法如下),如果您需要一些帮助来掌握 npm,然后查看 SitePoint 的适合初学者的 npm 教程。
在本文中,我们将着眼于使用Babel和webpack创建用于处理现代 JavaScript(在 Web 浏览器中运行)的构建设置。
这对于确保我们的现代 JavaScript 代码尤其能够与更广泛的浏览器兼容是必要的。
与大多数与 Web 相关的技术一样,JavaScript 一直在发展。在过去的好日子里,我们可以<script>在一个页面中添加几个标签,也许包括 jQuery 和几个插件,然后就可以了。
然而,自从引入 ES6 以来,事情变得越来越复杂。浏览器对新语言功能的支持通常不完整,随着 JavaScript 应用程序变得更加雄心勃勃,开发人员开始使用模块来组织他们的代码。反过来,这意味着如果您现在正在编写现代 JavaScript,则需要在您的流程中引入构建步骤。
从下面的链接中可以看出,从 ES6 转换到 ES5 显着增加了我们可以支持的浏览器数量。
- ES6 兼容性
- ES5 兼容性
构建系统的目的是使我们的代码为浏览器和生产环境做好准备所需的工作流程自动化。这可能包括诸如将代码转换为不同的标准、将 Sass 编译为 CSS、捆绑文件、压缩和压缩代码等步骤。为了确保这些是一致的可重复的,需要一个构建系统来从单个命令以已知顺序启动这些步骤。
先决条件为了继续进行,您需要同时安装Node.js 和 npm(它们打包在一起)。我建议使用nvm 之类的版本管理器来管理您的 Node 安装(方法如下),如果您需要一些帮助来掌握 npm,然后查看 SitePoint 的适合初学者的 npm 教程。
设置在您的计算机上的某个位置创建一个根文件夹,然后从您的终端/命令行导航到它。这将是您的<ROOT>文件夹。
用这个创建一个package.json文件:
npm init -y
注意:该-y标志使用默认设置创建文件,这意味着您不需要从命令行完成任何通常的详细信息。如果您愿意,可以稍后在您的代码编辑器中更改它们。
在您的<ROOT>文件夹中,创建目录src、src/js和public. 该src/js文件夹将是我们放置未处理源代码的位置,该文public件夹将是转译代码的最终位置。
使用 Babel 进行编译为了让自己继续前进,我们将安装babel-cli,它提供了将 ES6 转译为 ES5 的能力,以及babel-preset-env,它允许我们使用转译的代码来定位特定的浏览器版本。
npm install babel-cli babel-preset-env --save-dev
您现在应该在您的 中看到以下内容package.json:
"devDependencies": {
"babel-cli": "^6.26.0"
"babel-preset-env": "^1.6.1"
}
当我们在package.json文件中时,让我们将scripts部分更改为如下所示:
"scripts": {
"build": "babel src -d public"
}
这使我们能够通过脚本调用 Babel,而不是每次都直接从终端调用。如果您想了解有关 npm 脚本及其功能的更多信息,请查看此 SitePoint 教程。
最后,在我们可以测试 Babel 是否在做它的事情之前,我们需要创建一个.babelrc配置文件。这就是我们的babel-preset-env包将引用它的转译参数。
<ROOT>在您的目录中创建一个名为的新文件.babelrc并将以下内容粘贴到其中:
{
"presets": [
[
"env"
{
"targets": {
"browsers": ["last 2 versions" "safari >= 7"]
}
}
]
]
}
这将设置 Babel 为每个浏览器的最后两个版本以及 v7 或更高版本的 Safari 进行转换。其他选项可用,具体取决于您需要支持的浏览器。
保存后,我们现在可以使用使用 ES6 的示例 JavaScript 文件进行测试。出于本文的目的,我修改了leftpad的副本以在许多地方使用 ES6 语法:模板文字、箭头函数、const 和 let。
"use strict";
function leftPad(str len ch) {
const cache = [
""
" "
" "
" "
" "
" "
" "
" "
" "
" "
];
str = str "";
len = len - str.length;
if (len <= 0) return str;
if (!ch && ch !== 0) ch = " ";
ch = ch "";
if (ch === " " && len < 10)
return () => {
cache[len] str;
};
let pad = "";
while (true) {
if (len & 1) pad = ch;
len >>= 1;
if (len) ch = ch;
else break;
}
return `${pad}${str}`;
}
将其保存为src/js/leftpad.js终端并从终端运行以下命令:
npm run build
如果一切正常,您public现在应该在您的文件夹中找到一个名为js/leftpad.js. 如果你打开它,你会发现它不再包含任何 ES6 语法,看起来像这样:
"use strict";
function leftPad(str len ch) {
var cache = ["" " " " " " " " " " " " " " " " " " "];
str = str "";
len = len - str.length;
if (len <= 0) return str;
if (!ch && ch !== 0) ch = " ";
ch = ch "";
if (ch === " " && len < 10) return function () {
cache[len] str;
};
var pad = "";
while (true) {
if (len & 1) pad = ch;
len >>= 1;
if (len) ch = ch;else break;
}
return "" pad str;
}
使用 ES6 模块组织代码
ES6 模块是一个 JavaScript 文件,其中包含您希望提供给另一个 JavaScript 文件的函数、对象或原始值。你export从一个,import进入另一个。任何严肃的现代 JavaScript 项目都应该考虑使用模块。它们允许您将代码分解为独立的单元,从而使事情更容易维护;它们可以帮助您避免命名空间污染;它们有助于使您的代码更具可移植性和可重用性。
尽管大多数 ES6 语法在现代浏览器中都可以广泛使用,但模块还不是这样。在撰写本文时,它们在 Chrome、Safari(包括最新的 iOS 版本)和 Edge 中可用;它们隐藏在 Firefox 和 Opera 的旗帜后面;并且它们在 IE11 和大多数移动设备中都不可用(并且可能永远不会)。
在下一节中,我们将看看如何将模块集成到我们的构建设置中。
出口export 关键字允许我们使我们的 ES6 模块可用于其他文件,它为我们提供了两个选项——命名和默认。使用命名导出,每个模块可以有多个导出,而使用默认导出,每个模块只有一个。在需要导出多个值的情况下,命名导出特别有用。例如,您可能有一个包含许多实用功能的模块,这些实用功能需要在您的应用程序的各个位置提供。
所以让我们把我们的leftPad文件变成一个模块,然后我们可以在第二个文件中使用它。
命名导出要创建命名导出,请将以下内容添加到leftPad文件底部:
export { leftPad };
我们还可以"use strict";从文件顶部删除声明,因为模块默认以严格模式运行。
违约出口由于文件中只有一个函数要导出leftPad,因此它实际上可能是一个很好的export default替代方法:
export default function leftPad(str len ch) {
...
}
同样,您可以"use strict";从文件顶部删除声明。
进口为了使用导出的模块,我们现在需要将它们导入到我们希望使用它们的文件(模块)中。
对于该export default选项,可以使用您希望选择的任何名称导入导出的模块。例如,leftPad可以像这样导入模块:
import leftPad from './leftpad';
或者它可以作为另一个名称导入,如下所示:
import pineapple_fritter from './leftpad';
从功能上讲,两者的工作方式完全相同,但是使用与导出时相同的名称或使导入易于理解的名称显然是有意义的——也许导出的名称会与另一个变量名冲突接收模块。
对于命名导出选项,我们必须使用与导出时相同的名称导入模块。对于我们的示例模块,我们将以与使用export default语法类似的方式导入它,但在这种情况下,我们必须用花括号将导入的名称括起来:
import { leftPad } from './leftpad';
大括号对于命名导出是强制性的,如果不使用它们将会失败。
如果需要,可以在导入时更改命名导出的名称,为此,我们需要使用语法稍微修改我们的import [module] as [path]语法。与 一样export,有多种方法可以做到这一点,所有这些都在MDN 导入页面上有详细说明。
import { leftPad as pineapple_fritter } from './leftpad_es6';
同样,名称更改有点荒谬,但它说明了它们可以更改为任何内容的观点。您应该始终保持良好的命名习惯,当然,除非您正在编写准备水果食谱的例程。
使用导出的模块为了使用导出的leftPad模块,我在文件夹中创建了以下index.js文件src/js。在这里,我遍历一个序列号数组,并在它们前面加上零,使它们成为一个八字符的字符串。稍后,我们将利用它并将它们发布到 HTML 页面上的有序列表元素中。请注意,此示例使用默认导出语法:
import leftPad from './leftpad';
const serNos = [6934 23111 23114 1001 211161];
const strSNos = serNos.map(sn => leftPad(sn 8 '0'));
console.log(strSNos);
正如我们之前所做的,从<ROOT>目录运行构建脚本:
npm run build
Babel 现在将index.js在目录中创建一个文件public/js。与我们的leftPad.js文件一样,您应该看到 Babel 已经替换了所有 ES6 语法,只留下了 ES5 语法。您可能还注意到它已将 ES6 模块语法转换为基于 Node 的语法module.exports,这意味着我们可以从命令行运行它:
node public/js/index.js
// [ '00006934' '00023111' '00023114' '00001001' '00211161' ]
您的终端现在应该注销以零为前缀的字符串数组,以使它们全部为八个字符。完成之后,是时候看看 webpack 了。
介绍 webpack 并将其与 Babel 集成如前所述,ES6 模块允许 JavaScript 开发人员将他们的代码分解为可管理的块,但这样做的结果是这些块必须提供给请求浏览器,可能会向服务器添加数十个额外的 HTTP 请求——这我们真的应该避免。这就是webpack的用武之地。
webpack 是一个模块打包器。它的主要目的是通过跟踪所有依赖项来处理您的应用程序,然后将它们全部打包成一个或多个可以在浏览器中运行的包。但是,它可能远不止于此,具体取决于它的配置方式。
webpack 配置基于四个关键组件:
- 一个入口点
- 输出位置
- 装载机
- 插件
入口:这包含 webpack 可以识别其依赖项的应用程序的起点。
输出:这指定您希望将处理后的捆绑包保存在哪里。
加载器:这是一种将一个东西转换为输入并生成其他东西作为输出的方法。它们可以用来扩展 webpack 的能力来处理不仅仅是 JavaScript 文件,因此也可以将它们转换为有效的模块。
插件:这些用于将 webpack 的功能扩展到捆绑之外的其他任务中——例如缩小、linting 和优化。
<ROOT>要安装 webpack,请从您的目录中运行以下命令:
npm install webpack webpack-cli --save-dev
这会将 webpack 安装到项目本地,并且还可以通过添加webpack-cli. 您现在应该会看到package.json文件中列出了 webpack。当您在该文件中时,按如下方式修改脚本部分,以便它现在知道直接使用 webpack 而不是 Babel:
"scripts": {
"build": "webpack --config webpack.config.js"
}
正如你所看到的,这个脚本正在调用一个webpack.config.js文件,所以让我们在我们的<ROOT>目录中创建它,内容如下:
const path = require("path");
module.exports = {
mode: 'development'
entry: "./src/js/index.js"
output: {
path: path.resolve(__dirname "public")
filename: "bundle.js"
}
};
这或多或少是 webpack 所需的最简单的配置文件。您可以看到它使用了前面描述的输入和输出部分(它可以单独使用这些部分),但也包含一个mode: 'development'设置。
webpack 可以选择使用“开发”或“生产”模式。设置mode: 'development'优化了构建速度和调试,而mode: 'production'优化了运行时的执行速度和输出文件大小。Tobias Koppers 的文章“ webpack 4:模式和优化”中对模式进行了很好的解释,如果您希望了解更多关于如何在默认设置之外配置它们的信息。
接下来,从文件夹中删除所有文件public/js。然后重新运行:
npm run build
您会看到它现在包含一个./public/bundle.js文件。但是,打开新文件,我们开始使用的两个文件看起来完全不同。这是包含index.js代码的文件部分。即使它对我们的原始版本进行了相当大的修改,您仍然可以选择它的变量名:
/***/ "./src/js/index.js":
/*!*************************!*\
!*** ./src/js/index.js ***!
\*************************/
/*! no exports provided */
/***/ (function(module __webpack_exports__ __webpack_require__) {
"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _leftpad__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./leftpad */ \"./src/js/leftpad.js\");\n\n\nconst serNos = [6934 23111 23114 1001 211161];\nconst strSNos = serNos.map(sn => Object(_leftpad__WEBPACK_IMPORTED_MODULE_0__[\"default\"])(sn 8 '0'));\nconsole.log(strSNos);\n\n\n//# sourceURL=webpack:///./src/js/index.js?");
/***/ })
如果您node public/js/bundle.js从该<ROOT>文件夹运行,您会看到您得到与之前相同的结果。
转译如前所述,加载器允许我们将一种东西转换成另一种东西。在这种情况下,我们希望将 ES6 转换为 ES5。为此,我们需要更多的软件包:
npm install babel-loader babel-core --save-dev
要使用它们,webpack.config.js需要在输出部分之后添加一个模块部分,如下所示:
module.exports = {
entry: "./src/js/index.js"
output: {
path: path.resolve(__dirname "public/js")
filename: "bundle.js"
}
module: {
rules: [
{
test: /\.js$/
exclude: /(node_modules)/
use: {
loader: "babel-loader"
options: {
presets: ["babel-preset-env"]
}
}
}
]
}
};
这使用 regex 语句来识别要使用 转译的 JavaScript 文件babel-loader,同时排除node_modules文件夹中的任何内容。最后,babel-loader被告知使用babel-preset-env之前安装的包来建立.babelrc文件中设置的转译参数。
完成后,您可以重新运行:
npm run build
然后检查新的public/js/bundle.js,你会看到 ES6 语法的所有痕迹都消失了,但它仍然产生与以前相同的输出。
将其带到浏览器在构建了一个正常运行的 webpack 和 Babel 设置之后,是时候将我们所做的事情带到浏览器中了。需要一个小的 HTML 文件,该文件应在以下<ROOT>文件夹中创建:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width initial-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Webpack & Babel Demonstration</title>
</head>
<body>
<main>
<h1>Parts List</h1>
<ol id="part-list"></ol>
</main>
<script src="./public/js/bundle.js" charset="utf-8"></script>
</body>
</html>
它没有什么复杂的。需要注意的要点是<ol></ol>元素,数字数组将在其中,以及<script></script>结束标记之前的元素</body>,链接回./public/js/bundle.js文件。到现在为止还挺好。
需要更多的 JavaScript 来显示列表,所以让我们改变./src/js/index.js以实现它:
import leftPad from './leftpad';
const serNos = [6934 23111 23114 1001 211161];
const partEl = document.getElementById('part-list');
const strList = serNos.reduce(
(acc element) => acc = `<li>${leftPad(element 8 '0')}</li>` ''
);
partEl.innerHTML = strList;
现在,如果您index.html在浏览器中打开,您应该会看到一个有序列表,如下所示:
更进一步如上所述,我们的构建系统已经准备就绪。我们现在可以使用 webpack 打包我们的模块,并使用 Babel 将 ES6 代码转换为 ES5。
然而,为了转换我们的 ES6 代码,我们必须在npm run build每次进行更改时运行,这有点麻烦。
添加“手表”为了克服重复运行的需要npm run build,你可以在你的文件上设置一个'watch',并让 webpack 每次看到文件./src夹中的一个文件发生变化时自动重新编译。要实现这一点,请修改文件的scripts部分package.json,如下所示:
"scripts": {
"watch": "webpack --watch"
"build": "webpack --config webpack.config.js"
}
要检查它是否正常工作,npm run watch请从终端运行,您会看到它不再返回到命令提示符。现在返回并在数组中src/js/index.js添加一个额外的值并保存它。serNos我的现在看起来像这样:
const serNos = [ 6934 23111 23114 1001 211161 'abc'];
如果您现在检查终端,您会看到它已注销,并且它已重新运行 webpackbuild任务。返回浏览器并刷新时,您会看到添加到列表末尾的新值已使用leftPad.
自动刷新浏览器如果我们能够让 webpack 在每次进行更改时自动刷新浏览器,那就太好了。让我们通过安装一个名为webpack-dev-server. 不过,不要忘记先Ctrl c退出watch任务!
npm install webpack-dev-server --save-dev
完成后,让我们在package.json文件中添加一个新脚本来调用新包。该scripts部分现在应该包含以下内容:
"scripts": {
"watch": "webpack --watch"
"start": "webpack --watch & webpack-dev-server --open-page 'webpack-dev-server'"
"build": "webpack --config webpack.config.js"
}
注意--open-page添加到脚本末尾的标志。这告诉您在默认浏览器中使用其iframe 模式webpack-dev-server打开特定页面。
现在运行npm start,您应该会看到一个新的浏览器选项卡正在打开,http://localhost:8080/webpack-dev-server/其中显示了部件列表。要显示它'watch'正在工作,请转到src/js/index.js并将另一个新值添加到serNos数组的末尾。保存更改时,您应该注意到它们几乎立即反映在浏览器中。
完成此操作后,唯一剩下的就是将模式webpack.config.js设置为production. 一旦设置好,webpack 也会将它输出的代码缩小为./public/js/bundle.js. 您应该注意,如果mode未设置,webpack 将默认使用production配置。
结论在本文中,您了解了如何为现代 JavaScript 设置构建系统。最初,这使用 Babel 从命令行将 ES6 语法转换为 ES5。然后,您看到了如何使用 ES6 模块export和import关键字,如何集成 webpack 以执行捆绑任务,以及如何添加监视任务以在每次检测到源文件更改时自动运行 webpack。最后,您已经了解了如何安装webpack-dev-server以在每次进行更改时自动刷新页面。