Утомленный мозг руководство JavaScripter из современных инструментов интерфейса в 2018 году

1656588146 utomlennyj mozg rukovodstvo javascripter iz sovremennyh instrumentov interfejsa v 2018

автор Амин Мохамед Аджани

1*mbiAnHlVRgaTRr8tgNU5zg
Фото Ади Голдштейна на Unsplash

От менеджеров пакетов до ESLint, CommonJS до AMD и модулей ES6 до Babel и Webpack – это множество инструментов! В этой статье мы перенесем старое приложение AngularJS, где мы расшифруем инструменты СЕЙЧАС.

Я устал…

Да, я сегодня устал.

Это натолкнуло меня на мысль, что я мог бы остаться работать в продажах и не идти в обход к веб-разработке интерфейса. Но потом я понял, что фронтенд разработка для смелых сердец, и храбрые сердца не бросают. Они побеждают.

Поэтому я выбираю победу, написав что-нибудь стоящее для уставших жертв разработки интерфейса и его инструментов. Я буду писать о том, как я превратил код для начинающих в полноценную программу производственного уровня и инструменты, которые я настроил в процессе.

Давайте начнем!

То, что мы строим

Ничего изысканного. Мы создаем веб-приложение, которое получает некоторых случайных пользователей API и отображает его на интерфейсе. Будет иметь нет экстраординарной маршрутизации. Конечная цель статьи – научить вас привыкнуть к инструментам интерфейса.

Я использую AngularJS без шаблона, поэтому мы, не отвлекающиеся от CLI, оставляют нас без дыхания и поражаем в смех черной магии. Примечание: я использую AngularJS, а не Angular. AngularJS, потому что я не мог найти ни одной публикации, связанной с инструментами и комплектованием AngularJS.

Давайте начнем с создания файла индекса в нашем корневом каталоге.

<html>
<head>
    <title>Random User!</title>
    <link rel="stylesheet" href="
</head>
<body>
<div class="container">
    <h1 class="text-center">Random User!</h1>
</div>
<script src="
</body>

Старые добрые времена. Получили файл Angularjs и минимальный фреймворк CSS от CDN, а затем мы начинаем готовить наш код JavaScript и продолжаем добавлять его в индекс строку за строкой.

Но по мере того, как ваше приложение будет расти, вам нужно будет отслеживать все ваши зависимости (в этом случае Angular).

Введите менеджеры пакетов

Поэтому многие прибегают к наличию менеджера пакетов, который отслеживает версии зависимостей, которые они используют в своем проекте. Наиболее USP менеджер пакетов — это перейти к GitHub зависимости, загрузить его в свою папку и отслеживать загруженную версию. Это поможет вам не сломать код, если вы переместите свое репо и позже загрузите другую версию.

Были duojs, jspm, bower, npm, а теперь есть:

Давайте установите его. Нам это пригодится. Когда мы добавить зависимость в нашем приложении, yarn будет загружать материал и хранить его в папке node_modules. С этого момента, если вам нужен файл, вы можете ссылаться на src в свой индекс.

yarn add angular
1*MMK6im0fzHzttrpiHHqL5Q

Пока мы это делаем, давайте также добавим app.js, userController.js и userFactory.js в наш корневой каталог и свяжем их в наш индексный файл.

App.js:

/**
 * /app.js
 */

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

userFactory.js:

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

userController.js:

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

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="
</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>

Проблемы с таким подходом

Порядок нашего тега сценария должен находиться в этом конкретном порядке. app.js создает переменную app, а затем подключает ее к глобальному объекту окна. Эта переменная программы затем используется остальными файлами сценария. Это часто называют глобальным загрязнением пространства имен, и если вы все еще используете этот подход, не делайте этого. Кроме того, если мы в любой момент откроем любой файл JS, у нас нет представления о том, что содержит переменная программы.

Другая семантическая проблема этого кода состоит в том, что этот код использует анонимные функции. Анонимные функции являются как благом, так и бедствием для JavaScript. Всегда называйте свою анонимную функцию. Это облегчит отладку трасс стека.

Не было бы замечательно, если бы у нас была полиция JS, которая указывала бы нам на это, когда мы писали?

ESLint

ESLint – это линтер. Как сочетание кода с более строгой версией вас. Линтеры экономят ваше время, настраивая код еще до запуска программы. Также это заставляет вас и вашу команду соблюдать чистый код. Кто скажет не такому замечательному учителю?

Настройка ESLint

yarn add eslint eslint-config-airbnb eslint-config-airbnb-base -D

Мы будем использовать конфигурацию стиля Airbnb, которая проходит через наш код и указывает, где мы пишем код нестандартным способом. Вышеуказанная команда установит конфигурации в папку node_modules, но нам нужно будет указать ESLint использовать их. Создайте файл под названием .eslintrc.json и заполните его:

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

Стек расширений предписывает ESLint использовать правила Airbnb в дополнение к собственным правилам. Переменная env предписывает ESLint не кричать на нас, если мы используем такие переменные окно без его инициализации. Чтобы разметить все наши файлы, можно использовать символ подстановки *.

node_modules/.bin/eslint *.js

Давайте запустим ESLint для наших файлов и посмотрим, что произойдет.

1*F47YGCwPC3b-B08jqMd0Mw

Это все правила, указанные в руководстве по стилю Airbnb. Я оставлю вам исправить файлы. Линтер всегда лучше иметь с самого начала. Конечно, вы также можете отключить конкретное правило. Например, если вы предпочитаете без точки с запятой или стиль двойных кавычек вместо одинарных, их можно отключить. ESLint придаст вам эту упругость.

Модули

Теперь поговорим о модульности. При создании крупномасштабных приложений нам нужно иметь хорошо структурированный код, чтобы его было легче масштабировать. Мы ввели разделение проблем, объединив фрагменты кода в отдельные модули. JavaScript не поддерживал модули до появления ES6. Но концепция модульности появилась задолго до ES6.

CommonJS

В 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);
}

Если вы повозились с Node, вы можете обнаружить этот фрагмент кода очень знакомым. Но у этого стандарта есть и минусы, поскольку он синхронен. Это означает, что если validateUrl не является требуется, handleSubmit в строке 3 postController выше не выполняется. Код останавливается.

Эта идеология отлично работает в Node.js. В Node мы можем иметь много зависимостей перед запуском сервера. Например, настройка файлов журналов, подключение к базе данных в облаке, настройка секретных ключей. Но на передней части это не всегда нужно.

Определение асинхронного модуля (AMD)

Как видно из названия, он асинхронно загружает модули и имеет несколько преимуществ перед шаблонами 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;
  }

Это похоже на то, как мы вводим зависимости в AngularJS на строке 1.

Модули ES6

Поскольку комитет TC39 увидел, что разработчики используют внешние библиотеки, они явно нуждались в JavaScript для поддержки модулей. Поэтому они представили его в ES6. Давайте воспользуемся ими!

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


import { validateUrl } from './util';

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

Нет внешней библиотеки для вызова. Поддерживается импорт/экспорт. Но все еще есть версии браузеров, которые не полностью поддерживают все функции ES6. Это несоответствие поддержки браузером не помешало программистам написать следующее поколение JavaScript. Доступны такие инструменты, как babel, сканирующие через JavaScript и транспиляция к совместимому с браузером коду. И точно так, ваш код поддерживает старые браузеры, такие как IE (о, IE уже умрет!).

Babel и ES6

Ладно, давайте превратим наш старый 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: '
  });
  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);

Проблема с этим кодом

Этот код не будет работать. Поскольку ключевое слово let ES6 создает переменные с областью действия блока, и мы не можем снова определить переменную с областью действия блока внутри собственной области. Помните, мы все еще сидим в глобальном масштабе. Мы это поправим.

Причина, почему я попросил вас переработать код, состоит в том, что я хочу, чтобы вы использовали babel для этого и сами увидели магию. Пора запустить этот терминал.

yarn add babel-cli babel-preset-env

Это добавит babel-cli и babel-preset-env.

Плагины и пресеты Babel

Код проходит серию трансформаций и вы можете выбрать, какие типы трансформаций вам нужны. Вы можете превратить стрелочные функции в анонимные, трансформировать операторы распространения, преобразовывать циклы for…of и многое другое. Эти преобразования мы называем плагинами.

Вы можете выбрать типы трансформаций, которые вы хотите. Группы плагинов называются пресетами. Babel-preset-env создает движущуюся цель для вашего babel. Вы не указываете фактическую версию JavaScript, но просите babel отследить последнюю п версии всех браузеров.

Теперь создайте файл конфигурации babel: .babelrc и поместите его в корневую папку.

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

Теперь, если вы запустите следующую команду на своем терминале, babel выполнит свою работу. Давай, попробуй:

node_modules/.bin/babel *.js
1*P6hqhWvB52pMsILqo708Zw
я могу сделать всего столько экрана. Но вы получаете свер..

Прекрасные вещи, правда? Babel дал предварительный просмотр того, как будут выглядеть файлы, если бы он конвертировал файлы для нас.

Теперь давайте передохнем и подумаем, чего всего мы добились. Мы разбили файл JavaScript на многие файлы. Мы добавили линтер, чтобы он кричал на нас, если мы пишем смешной код. В будущем мы пишем JavaScript и делаем его доступным для браузера в понятной ему версии. Мы запачкали глобальное пространство имен, но мы сделали это отлично, что мы скоро исправим.

Будь только инструмент, который делает все это автоматически. Мы скажем ему взять наш код, запустить линтер для обнаружения каких-либо ошибок до того, как код попадет в производство, и транспилировать его в код, совместимый с браузером. Да, такой инструмент есть.

Давайте чертовски автоматизируем это.

Комплектация из Webpack

Сначала переместите все файлы JS в папку. А давайте воспользуемся стандартной мнемоникой и назовем папку строить. Кроме того, давайте переделаем наши файлы 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: '
    });
    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

Теперь создайте файл 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
    }
};

Если вы запустите Webpack, вы увидите все файлы, объединенные в один файл в папке dist.

webpack
1*Vz4cQWFXYZdkU-TCJAVyIg

блаженство.

Разборка конфигурации Webpack

Приветствую. Погладьте себя по спине. Вы объединяете свои файлы так, что они почти готовы к производству. Теперь поговорим о конфигурации. Я разберу это и скажу вам, что это каждый ключ. Чтобы узнать больше, вы всегда можете прочесть инструкцию.

Я прокомментировал большинство вещей. Здесь я говорю о том, что осталось:

Загрузчики Webpack (объект модуля)

Подумайте об этом как о цепочке блоков загрузки кода в конвейере. Последний в стеке (в нашем случае babel-loader) первый, который Webpack использует для загрузки фрагментов кода. Мы просим Webpack пройти наш код и сначала транспилировать его в ES5 с помощью babel-loader.

Объекту загрузчика также потребуется тестовый ключ. Он использует этот ключ, чтобы найти все файлы, которые ему нужно подобрать (в нашем случае, регулярное выражение, соответствующее файлам, оканчивающимся точкой JS). После переноса перейдите к следующему загрузчику (в нашем случае eslint-loader). И в конце запишите конфигурации из памяти в файл и выбросьте их в файл, который мы указали в объекте вывода.

Но это не то что делает наша конфигурация. Мы добавили enforce-pre к нашему загрузчику ESLint, потому что нам нужно сначала linting. Так как на выходе будет один файл. И этот файл будет в едва ли читаемом формате, если мы используем минификацию и обфускацию (что часто бывает в производстве). Линтер сойдет с ума, глядя на наш конечный код. Мы этого не хотим. Итак, Webpack будет первым и потом транспиляция.

Кроме этого, есть много загрузчиков, которые вы можете использовать, будь то для загрузки файлов стилей, SVG или шрифтов. Один загрузчик, который я почти всегда использую на работе – это html-loader.

Загрузчик HTML

В случае Angular, когда у нас есть шаблоны в директивах/компонентах, мы можем использовать html-загрузчик в Webpack.

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

Webpack преуспевает благодаря огромному сообществу, которое предлагает отличные загрузчики с превосходной документацией. Для всех ваших потребностей, скорее всего, написан по крайней мере один загрузчик.

Webpack Dev Server (devServer)

Сервер разработчика Webpack — это модуль, поставляемый отдельно от Webpack. Он разворачивает собственный сервер и наблюдает за изменяемыми нами файлами. Если вы внесете какие-либо изменения, WDS снова объединит их и обновит страницу. Если есть ошибки, он обновит страницу на экран наложения (настроенного с помощью клавиши наложения) и покажет вам ошибку прямо в браузере. И это очень быстро, поскольку все это выполняет в памяти, а не на жестком накопителе.

Конечно, чтобы заставить его работать, сначала нужно иметь базовый файл сборки (т.е. запустить Webpack как минимум один раз, чтобы иметь файл сборки). Получив это вы можете запустить эту команду. Он запустит сервер и будет обслуживать статические файлы, откроет вам браузер на порту 8080 по умолчанию и продолжит смотреть за переменами.

webpack-dev-server --open

Это!

Но это еще не конец, если подумать. Есть еще так много вещей, которые вы можете сделать. На работе мы используем Flow для статической проверки типа при кодировании. Статическая проверка типов смотрит на код и предупреждает вас, если вы, скажем, вызываете функции с неправильным типом аргументов. Вы также можете интегрировать это в Webpack.

Мы также используем Prettier для автоматического форматирования нашего кода при вводе. Это просто делает код более читабельным.

Любой дурак может написать код, который может понять компьютер. Хорошие программисты пишут код, который люди могут понять – Мартин Фаулер.

Вскоре я разместю это как плакат на своем столе.

Вывод

Поздравляю! Ты это сделал!

Если вы выжили, читая эту большую по жизни статью, позвольте мне дать вам «поздравления через Интернет» и сказать, что сегодня вы выиграли. Мне нелегко пережить JavaScript. Я хотел бы знать все это, работая над своим первым проектом в качестве пользователя интерфейса. Но я думаю, что для меня именно такова фронтенд разработка. Продолжайте учиться, продолжайте развиваться.

Пока я должен React, и вскоре я могу придумать еще одну статью, если вам понравилась эта. Возможно включить ReasonML, GraphQL или Redux. Если вам понравилась эта статья, ненавидели ее или у вас есть отзывы, скажите мне, пожалуйста.

Я живу в Twitter как @AminSpeaks и везде как @binarybaba.

Здоровья и Божьего случая.

Добавить комментарий

Ваш адрес email не будет опубликован.