2018年脑筋急转弯JavaScripter现代前端工具指南

by Amin Mohamed Ajani

通过阿明·穆罕默德·阿贾尼(Amin Mohamed Ajani)

2018年脑筋急转弯JavaScripter现代前端工具指南 (The brain-fatigued JavaScripter’s guide to modern frontend tooling in 2018)

From package managers to ESLint, CommonJS to AMD, and ES6 Modules to Babel and Webpack — that’s a lot of tools! In this article, we’ll migrate an old AngularJS app where we’ll decode the tools NOW.

从软件包管理器到ESLint,从CommonJS到AMD,再到ES6模块到Babel和Webpack,这是很多工具! 在本文中,我们将迁移一个旧的AngularJS应用,在此我们将立即解码工具。

我累了… (I’m tired…)

Yes, I got the fatigue today.

是的,我今天很疲劳

Which got me thinking, I could have stayed working in sales and not taken a detour to front end web development. But then I realized that front end development is for the brave hearts, and brave hearts don’t quit. They win.

这让我开始思考,我本可以继续从事销售工作,而不走弯路去开发前端Web。 但是后来我意识到前端开发是为了勇敢的人而做的,勇敢的人不会放弃。 他们赢了。

So I’m choosing to win by writing something worthwhile for fatigued victims of front end development and its tooling. I’ll be writing on how I transformed beginner code to a full-blown production level application, and the tools I configured in the process.

因此,我选择通过为前端开发及其工具的疲倦受害者编写有价值的东西来取胜。 我将撰写有关如何将初学者代码转换为成熟的生产级应用程序的文章,以及在过程中配置的工具。

Let’s get started!

让我们开始吧!

我们正在建立的 (What we’re building)

Nothing fancy. We’re building a web application that fetches some random users from an API and displays it on the front-end. It will have no routing extraordinare. The end goal of the article is to equip you to get used to frontend tooling.

没有什么花哨。 我们正在构建一个Web应用程序,该应用程序将从API中获取一些随机用户并将其显示在前端。 它将没有路由异常 本文的最终目标是使您习惯于前端工具。

I’m using AngularJS with no boilerplate, so we that aren’t abstracted away from CLIs that leaves us breathless and in the awe of black magic funnery. Note: I’m using AngularJS and not Angular. AngularJS because I couldn’t find any posts related to AngularJS tooling and bundling.

我正在使用没有样板的AngularJS,因此我们并没有摆脱CLI的困扰,因为CLI使我们感到喘不过气来,并为黑魔法狂欢感到敬畏。 注意:我使用的是AngularJS,而不是Angular。 AngularJS,因为我找不到与AngularJS工具和捆绑有关的任何文章。

Let’s start by creating an index file on our root directory.

让我们从在根目录上创建索引文件开始。

<html>
<head>
    <title>Random User!</title>
    <link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
</head>
<body>
<div class="container">
    <h1 class="text-center">Random User!</h1>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.0/angular.min.js"></script>
</body>

Good old days of yore. Got an Angularjs file and a minimal CSS framework from the CDN, and then we start cooking our JavaScript code and keep attaching it to the index line by line.

昔日的美好时光。 从CDN获得了一个Angularjs文件和一个最小CSS框架,然后我们开始烹饪我们JavaScript代码并将其逐行附加到索引中。

But as your app will grow, it will be necessary to keep track of all your dependencies (in this case, Angular).

但是随着您的应用程序的增长,有必要跟踪所有依赖项(在本例中为Angular)。

输入套件管理员 (Enter Package Managers)

So a lot of people resort to having a package manager which keeps track of the versions of dependencies they use on their project. A package manager’s single most USP is to goto the GitHub of the dependency, download it in your folder, and keep track of the version downloaded. This helps you not break your code if you move your repo and later download another version.

因此,许多人求助于包管理器,该包管理器跟踪他们在项目中使用的依赖项的版本。 软件包管理器最唯一的USP方法是转到依赖项的GitHub,将其下载到您的文件夹中,并跟踪下载的版本。 如果您移动存储库并随后下载另一个版本,则可以帮助您避免破坏代码。

There was duojs, jspm, bower, npm and now, there is:

duojsjspmbowernpm ,现在有:

Go ahead, install it. We’re gonna need it. When we add a dependency in our application, yarn will download the stuff and keep it inside the node_modules folder. From then on, if you need the file, you can src-reference into your index.

继续安装 。 我们将需要它。 当我们添加 在我们应用程序的依赖项中,yarn将下载内容并将其保存在node_modules文件夹中。 从那时起,如果您需要该文件,则可以对索引进行src引用。

yarn add angular

While we’re doing this, let’s also add app.js, userController.js, and userFactory.js files in our root directory and link them up into our index file.

在执行此操作的同时,我们还要在根目录中添加app.js,userController.js和userFactory.js文件,并将它们链接到索引文件中。

App.js:

App.js:

/**
 * /app.js
 */

var app = angular.module("RandomApp", []);

userFactory.js:

userFactory.js:

// /userFactory.js
app.factory("UserF", function($http) {
    var UserF = {};
    UserF.getUsers = function(){
        return $http({
            method: 'GET',
            url: 'https://www.reqres.in/api/users',
        })
    };
    return UserF;
});

userController.js:

userController.js:

// /userController.js
app.controller("userController", function($scope, UserF){
    $scope.users = [];
    UserF.getUsers()
        .then(function(res) {
            $scope.users = res.data.data;
        })
});

index.html:

index.html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Random User!</title>
    <link rel="stylesheet" href="https://unpkg.com/spectre.css/dist/spectre.min.css">
</head>
<body>
<div class="container" ng-app="RandomApp">
    <h1 class="text-center">Random User!</h1>
    <div ng-controller="userController">
        <div ng-repeat="user in users">
            <div class="card">
                <div class="card-image">
                    <img ng-src="{{user.avatar}}" class="img-responsive">
                </div>
                <div class="card-header">
                    <div class="card-title h5">{{user.first_name}} {{user.last_name}}</div>
                </div>
            </div>
        </div>
    </div>
</div>
<script src="node_modules/angular/angular.min.js"></script>
<script src="app.js"></script>
<script src="userController.js"></script>
<script src="userFactory.js"></script>
</body>
</html>
这种方法的问题 (Problems with this approach)

The order of our script tag must be in that specific order. app.js makes the variable app and then attaches it to the global window object. This app variable is then used by the rest of the script files. This is often called global namespace pollution, and if you are still using this approach, don’t. Further, if we open any one JS file in any given moment, we will have no idea what the app variable holds.

我们的脚本标签的顺序必须按照该特定顺序。 app.js制作变量app,然后将其附加到全局窗口对象。 然后,其余脚本文件将使用此应用程序变量。 这通常称为全局名称空间污染,如果您仍在使用此方法,请不要使用。 此外,如果在任何给定的时间打开任何一个JS文件,我们将不知道app变量的内容。

Another semantic problem with this code is that this code uses anonymous functions. Anonynous functions are both a boon and bane to JavaScript. Always name your anonymous function. It will make stack traces easier to debug.

此代码的另一个语义问题是该代码使用匿名函数。 匿名函数既是JavaScript的福音,也是祸根。 始终命名您的匿名函数。 这将使堆栈跟踪更易于调试。

Now wouldn’t it be cool if we could have a JS police that pointed out this stuff to us while we wrote?

现在,如果我们能有一个JS警察在我们写书时向我们指出这些东西,这不是很酷吗?

ESLint (ESLint)

ESLint is a linter. Kind of like code-pairing with a stricter version of you. Linters save time for you by debugging your code before you even run your application. Also it forces you and your team to follow clean code practices. Who says no to such an awesome teacher?

ESLint是短毛绒。 有点像与您的严格版本进行代码配对。 Linters通过甚至在运行应用程序之前调试代码来为您节省时间。 它还会迫使您和您的团队遵循干净的代码惯例。 谁对这样一位了不起的老师说不?

配置ESLint (Configuring ESLint)
yarn add eslint eslint-config-airbnb eslint-config-airbnb-base -D

We’ll be using Airbnb’s style configuration that runs through our code and tells us wherever we’re writing the code in a non-standard way. The above command will install the configurations in the node_modules folder, but we will need to tell ESLint to use these. Make a file called .eslintrc.json and fill it up with:

我们将使用Airbnb的样式配置 ,该样式配置贯穿我们的代码,并告诉我们无论我们在何处以非标准方式编写代码。 上面的命令会将配置安装在node_modules文件夹中,但是我们需要告诉ESLint使用这些配置。 制作一个名为.eslintrc.json的文件,并填写:

// .eslintrc.json
{
  "extends": [
    "airbnb/legacy"
  ],
  "env": {
    "browser": true
  }
}

The extends stack tells ESLint to use the Airbnb rules on top of its own rules. The env variable tells ESLint to not scream at us if we’re using variables like window without initializing it. To lint through all our files, you can use a wildcard *.

扩展堆栈告诉ESLint在自己的规则之上使用Airbnb规则。 如果我们使用诸如window之类的变量,则env变量告诉ESLint不要对我们大喊大叫 没有初始化它。 要遍历我们所有的文件,可以使用通配符*。

node_modules/.bin/eslint *.js

Let’s run ESLint on our files and see what happens.

让我们在文件上运行ESLint,看看会发生什么。

These are all rules defined in the Airbnb style guide. I’ll leave it up to you to fix your files. It’s always better to have a linter from the beginning. Of course, you can also switch off a particular rule. For example, if you prefer no-semicolon, or the double-quote style to single quote, you can switch them off. ESLint will give you that flexibility.

这些都是Airbnb样式指南中定义的规则。 我将由您自己来修复文件。 从一开始就拥有皮棉总是更好。 当然,您也可以关闭特定规则。 例如,如果您更喜欢不使用分号或双引号样式而不是单引号,则可以将其关闭。 ESLint将为您提供这种灵活性。

模组 (Modules)

Now let’s talk about modularity. When making large scale applications, we need to have our code well-structured so that it’s easier to scale. We put in place a separation of concerns by grouping code pieces in separate modules. JavaScript didn’t support modules until ES6 came along. But the concept of modularity came long before ES6.

现在让我们谈谈模块化。 在进行大规模应用程序时,我们需要使代码结构合理,以便于扩展。 通过将代码段分组在单独的模块中,我们将关注点分离。 直到ES6出现,JavaScript才支持模块。 但是模块化的概念早于ES6。

普通JS (CommonJS)

Before ES6, this standard was adopted as a pattern where you write your piece of code and tell the environment to export that piece. And then you’d use a library like RequireJS to import the module.

在ES6之前,此标准被用作一种模式,您可以在其中编写代码并告诉环境导出该代码。 然后,您将使用RequireJS之类的库来导入模块。

// util.js
module.export = {
    noop: function(){},
    validateUrl: function(s){
      return s.matches(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/)
    } 
};
// postController.js
var validateUrl = require('./util').validateUrl;
var handleSubmit = function handleSubmit(e) {
    if(!validateUrl(e.target.value)) {
       return;
    }
    submitUrl(e.target.value);
}

If you’ve tinkered around with Node, you may find that piece of code very familiar. But there are downsides to this standard, because it’s synchronous. Which means that unless validateUrl is required, handleSubmit on Line 3 of postController above isn’t executed. The code halts.

如果您对Node有所了解,您可能会发现这段代码非常熟悉。 但是该标准存在缺点,因为它是同步的。 这意味着,除非需要 validateUrl,handleSubmit上PostController中的第3行以上,不执行。 代码停止。

This ideology works fine in Node.js. In Node, we can have a lot of dependencies before starting a server. For example, configuring log files, connecting to the DB on cloud, configuring secret keys. But on the front end, it is not always required.

这种意识形态在Node.js中运行良好。 在Node中,启动服务器之前我们可能有很多依赖项。 例如,配置日志文件,连接到云上的数据库,配置密钥。 但是在前端,并不总是必需的。

异步模块定义(AMD) (Asynchronous Module Definition (AMD))

Like the name suggests, it asynchronously loads modules and has a few more advantages over CommonJS patterns. Here’s how the code looks like in AMD (I added a couple of functions). Do you see something familiar?

顾名思义,它异步加载模块,并且比CommonJS模式具有更多优势 。 这是代码在AMD中的样子(我添加了几个功能)。 你看到熟悉的东西吗?

define(['validateSpam', 'blockUser', function(validateSpam, blockUser){
  return {
    noop: function(){},
    validateUrl: function(s) {
      return s.matches(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/)
    },
    validateSpammyComment: function validateSpammyComment(comment, userID) {
      if(validateSpam(comment)) {
        blockUser(userID);
        return false;
      }
      return true;
  }

It kind of feels like the way we Inject Dependencies in AngularJS on Line 1.

感觉就像我们在第1行的AngularJS中注入依赖项的方式一样。

ES6模块 (ES6 Modules)

Since the committee at TC39 saw developers using external libraries, they clearly felt the need for JavaScript to support modules. So they introduced them in ES6. Let’s use them!

由于TC39的委员会看到开发人员正在使用外部库,所以他们显然感到需要JavaScript支持模块。 因此他们在ES6中引入了它们。 让我们使用它们!

utils.js:

utils.js:

function noop(){};
function validateUrl(s) {
  return s.matches(/https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/)
}
export {
  noop,
  validateUrl
}

postController:js

postController:js

import { validateUrl } from './util';

var handleSubmit = function handleSubmit(e) {
    if(!validateUrl(e.target.value)) {
       return;
    }
    submitUrl(e.target.value);
}

No external library to call. Import/export natively supported. But there are still versions of browsers which do not completely support all the features of ES6. This inconsistency of browser support didn’t stop programmers from writing the next generation of JavaScript. Tools like babel are available that scan through the JavaScript and transpile it down to browser compatible code. And just like that, your code supports older browsers like IE (oh IE die already!).

没有外部库可调用。 本机支持导入/导出。 但是仍然有一些版本的浏览器不完全支持ES6的所有功能 。 浏览器支持的这种不一致并没有阻止程序员编写下一代JavaScript。 像工具巴贝尔是可用的扫描通过JavaScript和transpile下来到浏览器兼容的代码。 就像那样,您的代码支持IE等较旧的浏览器(哦IE已经死了!)。

Babel and ES6

Babel和ES6

Okay, so let’s convert our old JavaScript to newer JavaScript. A little bit so that we can add some modularity. All this while, let’s keep our linter from yelling.

好的,让我们将旧JavaScript转换为较新JavaScript。 一点点,以便我们可以添加一些模块化。 在这期间,让我们不要让小动物大喊大叫。

// /userFactory.js
let angular = window.angular;
let app = angular.module('RandomApp');

/**
 * A User factory which gets the user list
 * @param $http
 */

let userFactory = $http => {
  let UserF = {};
  UserF.getUsers = () => $http({
    method: 'GET',
    url: 'https://www.reqres.in/api/users'
  });
  return UserF;
};
app.factory('UserF', userFactory);
// /userController.js

let angular = window.angular;
let app = angular.module('RandomApp');

/**
 * Controls the user
 * @param $scope
 * @param UserF
 */
let userController = ($scope, UserF) => {
  $scope.users = [];
  UserF.getUsers().then(res => $scope.users = res.data.data);
};
userController.$inject = ['$scope', 'UserFactory'];

app.controller('userController', userController);
此代码有问题 (Problem with this code)

This code won’t work. Because the let keyword of ES6 creates block scoped variables, and we can’t redefine a block scoped variable inside it’s own scope again. Remember: we’re still sitting on the global scope. We’ll fix this.

此代码无效。 由于ES6的let关键字创建了块范围变量,因此我们无法在其自身范围内重新定义块范围变量。 记住:我们仍然坐在全球范围内。 我们会修好的。

The reason why I asked you to refactor the code is because I want you to use babel on this and see the magic yourself. Time to fire up that terminal.

我之所以要求您重构代码,是因为我希望您对此使用babel并亲自查看魔术。 是时候启动该终端了。

yarn add babel-cli babel-preset-env

This will add babel-cli and babel-preset-env.

这将添加babel-cli和babel-preset-env。

Babel插件和预设 (Babel plugins and presets)

The code goes through a series of transformations, and you can choose what kinds of transformations you want. You can have it convert arrow functions to anonymous, transform spread operators, transform for…of loops and a lot more. These transformations are what we call plugins.

该代码经过一系列转换,您可以选择所需的转换类型。 您可以将其箭头函数转换为匿名函数,转换散布运算符,转换for ... of循环等等。 这些转换就是我们所说的插件。

You can pick and choose what kinds of transformations you want. Groups of plugins are called presets. Babel-preset-env creates a moving target for your babel. You are not pin-pointing the actual version of JavaScript, but you are asking babel to track the last n versions of all browsers.

您可以选择所需的转换类型。 插件组称为预设。 Babel-preset-env为您的babel创建一个移动目标。 您并未指出JavaScript的实际版本,而是要求babel跟踪所有浏览器的最后n个版本。

Now make a babel configuration file: .babelrc and place it in the root folder.

现在创建一个babel配置文件:.babelrc并将其放置在根文件夹中。

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": "last 2 versions"
      }
    }]
  ]
}

Now, if you run the following command on your terminal, babel will do its job. Go ahead, try it out:

现在,如果您在终端上运行以下命令,babel将完成其工作。 继续尝试一下:

node_modules/.bin/babel *.js

Nifty stuff, right? Babel gave a preview of how the files will look if it were to convert the files for us.

漂亮的东西,对不对? Babel预览了如果要为我们转换文件的文件外观。

Now let’s take a breather and think about what all we’ve accomplished so far. We’ve broken down a JavaScript file into many files. We’ve added a linter so that it yells at us if we write funny code. We’re writing JavaScript in the future and making it available to the browser in a version it understands. We’ve polluted the global namespace, but we’ve done it awesomely which we will fix soon.

现在让我们喘口气,想一想到目前为止我们已经完成了什么。 我们已经将JavaScript文件分解为许多文件。 我们添加了一个linter,以便在我们编写有趣的代码时大吼大叫。 我们会在将来编写JavaScript,并以其理解的版本将其提供给浏览器。 我们已经污染了全局名称空间,但是我们已经做到了,我们将尽快修复它。

If only there was a tool that does all that automatically. We’d tell it to take our code, run the linter for any errors before the code hits production, and transpile it to browser compatible code. Yes, there is such a tool.

如果只有一个工具可以自动执行所有操作。 我们告诉它接受我们的代码,在代码上线之前运行linter以防任何错误,然后将其转换为浏览器兼容代码。 是的,有这样的工具。

Let’s automate the hell out of this.

让我们自动完成这个任务。

与Webpack捆绑 (Bundling with Webpack)

First, move all JS files into a folder. And let’s use standard mnemonics and name the folder build. Also, let’s refactor our JavaScript files so that we can have all our files built up in a single file.

首先,将所有JS文件移动到一个文件夹中。 让我们使用标准助记符并将文件夹命名为build 。 另外,让我们重构JavaScript文件,以便将所有文件构建在一个文件中。

// /build/userController.js

/**
 * Controls the user
 * @param $scope
 * @param UserF
 */
let userController = ($scope, UserF) => {
    $scope.users = [];
    UserF.getUsers().then(res => $scope.users = res.data.data);
};
userController.$inject = ['$scope', 'userFactory'];

export default userController;
// /build/userFactory.js
/**
 * A User factory which gets the user list
 * @param $http
 */

let userFactory = $http => {
    let UserF = {};
    UserF.getUsers = () => $http({
        method: 'GET',
        url: 'https://www.reqres.in/api/users'
    });
    return UserF;
};
userFactory.$inject = ['$http'];

export default userFactory;
// /build/app.js
import angular from 'angular';

import userController from './userController';
import userFactory from './userFactory';

angular.module('RandomApp', [])
  .factory('userFactory', userFactory)
  .controller('userController', userController);
yarn add webpack webpack-dev-server babel-loader eslint-loader -D

And now, create a webpack.config.js file:

现在,创建一个webpack.config.js文件:

var path = require('path');

module.exports = {
    mode: 'development', // tells webpack that this is a development build. the 'production' switch will minify the code among other things
    devtool: 'cheap-eval-source-map', // generate source maps for better debugging and dont take much time.
    context: __dirname, // since this runs in a node environment, webpack will need the current directory name
    entry: './build/app.js', // take this file and add to the bundled file whatever this file imports
    output: {
        path: path.join(__dirname, 'dist'), // output this in a dist folder
        filename: 'bundle.js' // and name it bundle.js
    },
  // read medium post to know what's module and devServer because I dont have much room for comments
    module: {
      rules: [{
        enforce: 'pre',
        loader: 'eslint-loader',
        test: /\.js$/
      }, {
        loader: 'babel-loader',
        test: /\.js$/
      }]
    },
    devServer: {
        publicPath: '/dist/',
        filename: 'bundle.js',
        historyApiFallback: true,
        overlay: true
    }
};

If you now fire up Webpack, you will see all files bundled up in a single file in a dist folder.

如果现在启动Webpack,您将看到所有文件捆绑在dist文件夹中的单个文件中。

webpack

Bliss.

极乐。

剖析Webpack配置 (Dissecting Webpack Configuration)

Congratulations. Give yourself a pat on the back. You bundled your files so that they’re almost production ready. Now let’s talk about the configuration. I’ll break it down and tell you exactly what each key is. For more, you can always read the manual.

恭喜你 拍拍自己的背部。 您捆绑了文件,以便它们几乎可以投入生产。 现在让我们谈谈配置。 我将分解它,并告诉您每个键的确切含义。 有关更多信息, 您可以随时阅读手册

I’ve commented most of the stuff. Here, I talk about the left out stuff:

我评论了大多数内容。 在这里,我谈论剩下的东西:

Webpack加载程序(模块对象) (Webpack Loaders (module object))

Think of this as a chain of code-loading units in a pipeline. The last one in the stack (babel-loader in our case) is the first one which Webpack uses for loading the code chunks. We’re asking Webpack to go through our code and transpile it first into ES5 using the babel-loader.

可以将其视为管道中的一系列代码加载单元。 堆栈中的最后一个(在我们的例子中是babel-loader)是Webpack用于加载代码块的第一个。 我们要求Webpack浏览我们的代码,然后使用babel-loader将其首先转换为ES5。

A loader object will also need a test key. It uses this key to find all files it needs to pick up (in our case, a regex that matches files ending with the extension dot JS). Once transpiled, proceed to the next loader (eslint-loader in our case). And in the end, write the changes from memory to a file and dump it in the file which we’ve specified in the output object.

加载程序对象还将需要测试密钥。 它使用此键来查找需要提取的所有文件(在我们的示例中,是一个匹配以扩展名JS结尾的文件的正则表达式)。 编译后,继续进行下一个加载程序(在本例中为eslint加载程序)。 最后,将更改从内存写入文件,然后将其转储到我们在输出对象中指定的文件中。

But that’s not what our config does. We’ve added an enforce-pre on our ESLint loader because we want the linting first. Because the output will be a single file. And that file will be in a barely human readable format if we use minification and obfuscation (which is often the case in production). The Linter will go crazy looking at our end code. We don’t want that. So Webpack will lint first and then transpile.

但这不是我们的配置所做的。 我们在ESLint加载器上添加了一个preforce-pre,因为我们要先掉毛。 因为输出将是单个文件。 如果我们使用缩小和模糊处理 (在生产中通常是这种情况),那么该文件将几乎是人类可读的格式。 Linter会疯狂查看我们的最终代码。 我们不想要那个。 因此,Webpack会先将掉毛, 然后再进行移植。

Apart from these, there are many loaders you can use, be it to load your style files, your SVGs, or fonts. One loader that I almost always end up using at work is the html-loader.

除此之外,您还可以使用许多加载程序,无论是加载样式文件,SVG还是字体。 我几乎总是在工作中最终使用的一个加载器是html-loader。

HTML加载器 (HTML loader)

In the case of Angular, when we have templates in directives/components, we can use an html-loader in Webpack.

对于Angular,当我们在指令/组件中有模板时,可以在Webpack中使用html-loader。

templateUrl: './users/partial/user.tpl.html' // instead of this,
templateUrl: require('./users/partial/user.tpl.html')

Webpack thrives on a super huge community which comes up with awesome loaders with great documentation. For all your needs, chances are, there is at least one loader written.

Webpack在一个庞大的社区中蓬勃发展,该社区提供了很棒的加载程序以及出色的文档。 为了满足您的所有需求,至少要编写一个装载程序。

Webpack开发服务器(devServer) (Webpack Dev Server (devServer))

Webpack dev server is a module that comes separate from Webpack. It spins up its own server and watches the files we change. If you make any changes, the WDS will bundle it again and refresh the page. If there are errors, it will refresh the page to an overlay screen (configured by the overlay key) and show you the error right on the browser. And it’s super fast because it does all that in the memory and not on the hard storage.

Webpack开发服务器是独立于Webpack的模块。 它启动自己的服务器并监视我们更改的文件。 如果进行任何更改,WDS将再次捆绑它并刷新页面。 如果有错误,它将刷新页面到覆盖屏幕(由覆盖键配置),并在浏览器上直接向您显示错误。 而且它之所以超快速,是因为它在内存中而不是在硬盘上完成所有操作。

Of course, to get it to work, you first need to have a base build file (that is, run Webpack at least once to have a build file). Once you have that, you can fire up this command. It will start the server and serve the static files, open the browser for you on port 8080 by default, and keep watching the changes.

当然,要使其正常工作,首先需要具有一个基本的构建文件(即,至少运行一次Webpack以获得一个构建文件)。 一旦有了它,就可以启动该命令。 它将启动服务器并提供静态文件,默认情况下在端口8080上为您打开浏览器,并继续观察更改。

webpack-dev-server --open

That’s it!

而已!

But this is not the end of it if you think about it. There are still so many things you can do. At work, we use Flow for static type check while we code. A static type checker looks at your code and warns you if you’re, say, calling functions with the wrong type of arguments. You can integrate that as well in Webpack.

但是,如果您考虑一下,这还不是终点。 您仍然可以做很多事情。 在工作中,我们在编码时使用Flow进行静态类型检查。 静态类型检查器会查看您的代码,并警告您,例如,如果您使用错误的参数类型调用函数。 您也可以将其集成到Webpack中。

We also use Prettier to format our code automatically as we type. It just makes the code more readable.

我们还使用Prettier在键入时自动格式化代码。 它只是使代码更具可读性。

Any fool can write code that a computer can understand. Good programmers write code that humans can understand — Martin Fowler.
任何傻瓜都可以编写计算机可以理解的代码。 优秀的程序员编写了人类可以理解的代码-Martin Fowler。

I’m going to put that up as a poster on my desk soon.

我打算把它作为海报贴在我的桌子上。

结论 (Conclusion)

Congratulations! You did it!

恭喜你! 你做到了!

If you survived reading this larger than life article, let me give you an over-the-internet-hi-five and tell you that today, you won. Surviving JavaScript is not easy for me. I wish I could have known all this while working on my first project as a UI guy. But I guess that’s how front-end development is for me. Keep learning, keep evolving.

如果您在阅读这篇比生活更重要的文章时幸免于难,请允许我给您提供一个互联网五喜,并告诉您今天您赢了。 生存JavaScript对我来说并不容易。 我希望当我作为UI用户从事第一个项目时,能早已了解所有这一切。 但是我想这就是前端开发对我而言的方式。 不断学习,不断发展。

I’m tinkering with React for now, and I soon may come up with another article if you liked this one. Maybe include ReasonML, GraphQL or Redux. If you liked this article or hated it or have some feedback, please do tell me.

我现在正在修改React,如果您喜欢这篇文章,我很快可能会想出另一篇文章。 可能包括ReasonMLGraphQLRedux 。 如果您喜欢或讨厌这篇文章或有任何反馈,请告诉我。

I live on twitter as @AminSpeaks and everywhere else as @binarybaba.

我在Twitter上以@AminSpeaks身份生活 ,在其他地方则以@binarybaba身份生活。

Cheers and Godspeed.

干杯和Godspeed。

翻译自: https://www.freecodecamp.org/news/the-brain-fatigued-javascripters-guide-to-modern-frontend-tooling-in-2018-9818a04e9ec5/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值