portaldacalheta.pt
  • Основен
  • Agile Talent
  • Растеж На Приходите
  • Мобилен Дизайн
  • Управление На Проекти
Технология

Webpack или Browserify & Gulp: Кое е по-добро?



Тъй като уеб приложенията стават все по-сложни, превръщането на вашето уеб приложение в мащабиращо се от изключителна важност. Докато в миналото писането на ad-hoc JavaScript и jQuery би било достатъчно, в наши дни изграждането на уеб приложение изисква много по-голяма степен на дисциплина и официални практики за разработване на софтуер, като например:

  • Единични тестове, за да се гарантира, че модификациите на вашия код не нарушават съществуващата функционалност
  • Обвързване за осигуряване на последователен стил на кодиране без грешки
  • Производствени компилации, които се различават от компилациите за развитие

Мрежата предоставя и някои свои уникални предизвикателства за развитие. Например, тъй като уеб страниците правят много асинхронни заявки, производителността на вашето уеб приложение може значително да се влоши от необходимостта да изисква стотици JS и CSS файлове, всеки със свои собствени малки режийни (заглавки, ръкостискания и т.н.). Този конкретен проблем често може да бъде разрешен чрез групиране на файловете, така че заявявате само един пакет JS и CSS файл, а не стотици отделни.



Компромиси за пакетиране на инструменти: Webpack срещу Browserify



Кой инструмент за пакетиране трябва да използвате: Webpack или Browserify + Gulp? Ето ръководството за избор. Tweet

Също така е доста често да се използват езикови препроцесори като SASS и JSX, които се компилират в собствени JS и CSS, както и JS транпилатори като Babel, за да се възползват от ES6 кода, като същевременно се поддържа ES5 съвместимост.



Това се равнява на значителен брой задачи, които нямат нищо общо с писането на логиката на самото уеб приложение. Тук влизат бегачите на задачи. Целта на бегач на задачи е да автоматизира всички тези задачи, така че да можете да се възползвате от подобрена среда за разработка, като същевременно се фокусирате върху писането на приложението си. След като бегачът на задачите е конфигуриран, всичко, което трябва да направите, е да извикате една команда в терминал.

Ще използвам Глътка като бегач на задачи, защото е много удобен за разработчици, лесен за научаване и лесно разбираем.



Кратко въведение в Gulp

API на Gulp се състои от четири функции:

какво мога да направя с програмирането на c
  • gulp.src
  • gulp.dest
  • gulp.task
  • gulp.watch

Как работи Gulp



Ето например примерна задача, която използва три от тези четири функции:

gulp.task('my-first-task', function() { gulp.src('/public/js/**/*.js') .pipe(concat()) .pipe(minify()) .pipe(gulp.dest('build')) });

Когато my-first-task се изпълнява, всички файлове, съответстващи на глобус модел /public/js/**/*.js се минифицират и след това се прехвърлят в build папка.



Красотата на това е в .pipe() верига. Вземете набор от входни файлове, прекарайте ги през поредица от трансформации, след което върнете изходните файлове. За да направят нещата още по-удобни, действителните трансформации на тръбопроводи, като minify(), често се извършват от NPM библиотеки. В резултат на това е много рядко на практика, че трябва да напишете свои собствени трансформации, освен да преименувате файлове в тръбата.

Следващата стъпка за разбиране на Gulp е разбирането на масива от зависимости на задачите.



gulp.task('my-second-task', ['lint', 'bundle'], function() { ... });

Тук, my-second-task изпълнява функцията за обратно извикване само след lint и bundle задачите са изпълнени. Това позволява разделяне на проблемите: Създавате поредица от малки задачи с една отговорност, като преобразуване LESS до CSS и създайте вид главна задача, която просто извиква всички останали задачи чрез масива от зависимости на задачите.

И накрая, имаме gulp.watch, който наблюдава глобален модел на файл за промени и когато се открие промяна, изпълнява поредица от задачи.



gulp.task('my-third-task', function() { gulp.watch('/public/js/**/*.js', ['lint', 'reload']) })

В горния пример всички промени във файл, съответстващи на /public/js/**/*.js би задействал lint и reload задача. Честа употреба на gulp.watch е да задействате презареждане на живо в браузъра, функция, толкова полезна за разработка, че няма да можете да живеете без нея, след като сте я изпитали.

И точно така разбирате всичко, което наистина трябва да знаете за gulp.

Къде се вписва Webpack?

Как работи Webpack

Когато използвате шаблона CommonJS, групирането на JavaScript файлове не е толкова просто, колкото обединяването им. По-скоро имате входна точка (обикновено се нарича index.js или app.js) с поредица от require или import изявления в горната част на файла:

ES5

var Component1 = require('./components/Component1'); var Component2 = require('./components/Component2');

ES6

import Component1 from './components/Component1'; import Component2 from './components/Component2';

Зависимостите трябва да бъдат разрешени преди оставащия код в app.js и тези зависимости могат да имат допълнителни зависимости за разрешаване. Освен това бихте могли require една и съща зависимост на няколко места във вашето приложение, но вие искате да разрешите тази зависимост само веднъж. Както можете да си представите, след като имате дърво на зависимости на няколко нива, процесът на групиране на вашия JavaScript става доста сложен. Това е мястото, където пакети като Browserify и Webpack влизат.

Защо разработчиците използват Webpack вместо Gulp?

Webpack е пакет, докато Gulp е бегач на задачи, така че бихте очаквали да видите тези два инструмента, често използвани заедно. Вместо това има нарастваща тенденция, особено сред общността на React, да се използва Webpack вместо на Гълп. Защо е това?

Просто казано, Webpack е толкова мощен инструмент, че вече може да изпълнява по-голямата част от задачите, които иначе бихте направили чрез бегач на задачи. Например Webpack вече предлага опции за минимизиране и източници за вашия пакет. В допълнение, Webpack може да се изпълнява като междинен софтуер чрез персонализиран сървър, наречен webpack-dev-server, който поддържа както презареждане на живо, така и горещо презареждане (за тези функции ще говорим по-късно). Използвайки товарачи, можете също да добавите ES6 към ES5 транспилация и CSS предварително и след процесори. Това всъщност просто оставя модулните тестове и свързването като основни задачи, с които Webpack не може да се справи самостоятелно. Като се има предвид, че сме намалили поне половин дузина потенциални гълтачни задачи на две, много разработчици предпочитат вместо това да използват директно NPM скриптове, тъй като това избягва режийните разходи за добавяне на Gulp към проекта (за което също ще говорим по-късно) .

Основният недостатък на използването на Webpack е, че е доста трудно да се конфигурира, което е непривлекателно, ако се опитвате бързо да стартирате и стартирате проект.

Нашите 3 настройки на бегач на задачи

Ще създам проект с три различни настройки на бегач на задачи. Всяка настройка ще изпълнява следните задачи:

  • Настройте сървър за разработка с презареждане на живо при наблюдавани промени в файлове
  • Сглобете нашите JS и CSS файлове (включително ES6 към ES5 транпилация, SASS към CSS преобразуване и изходни карти) по мащабируем начин при наблюдавани промени на файлове
  • Стартирайте модулни тестове или като самостоятелна задача, или в режим на гледане
  • Стартирайте свързването или като самостоятелна задача, или в режим на гледане
  • Осигурете възможност за изпълнение на всичко по-горе чрез една команда в терминала
  • Имате друга команда за създаване на производствен пакет с минимизиране и други оптимизации

Нашите три настройки ще бъдат:

  • Gulp + Browserify
  • Gulp + Webpack
  • Webpack + NPM скриптове

Приложението ще използва Реагирайте за предния край. Първоначално исках да използвам фреймворк агностичен подход, но използването на React всъщност опростява отговорностите на бегача на задачи, тъй като е необходим само един HTML файл, а React работи много добре с шаблона CommonJS.

php unicode към utf 8

Ние ще покрием предимствата и недостатъците на всяка настройка, за да можете да вземете информирано решение за това какъв тип настройка най-добре отговаря на нуждите на вашия проект.

Настроих хранилище на Git с три клона, по един за всеки подход ( връзка ). Тестването на всяка настройка е толкова просто, колкото:

git checkout npm prune (optional) npm install gulp (or npm start, depending on the setup)

Нека разгледаме подробно кода във всеки клон ...

Общ код

Структура на папката

- app - components - fonts - styles - index.html - index.js - index.test.js - routes.js

index.html

Прав HTML файл. Приложението React се зарежда и ние използваме само един пакет JS и CSS. Всъщност в нашата настройка за разработка на Webpack дори няма да имаме нужда от bundle.css.

index.js

Това действа като JS входна точка на нашето приложение. По същество просто зареждаме React Router в div с идентификатор app че споменахме по-рано.

routes.js

Този файл определя нашите маршрути. URL адресите /, /about и /contact са картографирани на HomePage, AboutPage и ContactPage компоненти, съответно.

index.test.js

Това е поредица от единични тестове, които тестват собственото поведение на JavaScript. В реално приложение за качество на продукцията бихте написали единичен тест за React компонент (поне такива, които манипулират състоянието), тествайки специфично за React поведение. За целите на тази публикация обаче е достатъчно просто да имате функционален единичен тест, който може да работи в режим на гледане.

компоненти / App.js

Това може да се разглежда като контейнер за всички наши изгледи на страници. Всяка страница съдържа както компонент, така и this.props.children, който изчислява самия изглед на страницата (ex / ContactPage ако е в /contact в браузъра).

компоненти / начало / HomePage.js

Това е нашият домашен изглед. Реших да използвам react-bootstrap тъй като мрежата на bootstrap е отлична за създаване на отзивчиви страници. С правилното използване на bootstrap, броят на медийните заявки, които трябва да напишете за по-малки прозорци, е драстично намален.

Останалите компоненти (Header, AboutPage, ContactPage) са структурирани по подобен начин (react-bootstrap маркиране, без манипулация на състоянието).

Сега нека поговорим повече за стила.

Подход за стилизиране на CSS

Моят предпочитан подход за стилизиране на компонентите на React е да има по една таблица със стилове на компонент, чиито стилове са обхванати, за да се прилагат само за този специфичен компонент. Ще забележите, че във всеки от моите React компоненти, най-високото ниво div има име на клас, съответстващо на името на компонента. Така например, HomePage.js има своята маркировка, обгърната от:

...

Има и асоцииран HomePage.scss файл, който е структуриран, както следва:

@import '../../styles/variables'; .HomePage { // Content here }

Защо този подход е толкова полезен? Резултатът е силно модулен CSS, който до голяма степен елиминира проблема с нежеланото каскадно поведение.

Да предположим, че имаме два React компонента, Component1 и Component2. И в двата случая искаме да заменим h2 размер на шрифта.

/* Component1.scss */ .Component1 { h2 { font-size: 30px; } } /* Component2.scss */ .Component2 { h2 { font-size: 60px; } }

h2 размер на шрифта от Component1 и Component2 са независими, независимо дали компонентите са съседни, или единият компонент е вложен вътре в другия. В идеалния случай това означава, че стилът на компонента е напълно самостоятелен, което означава, че компонентът ще изглежда абсолютно по същия начин, независимо къде е поставен във вашата маркировка. В действителност не винаги е толкова просто, но със сигурност е огромна стъпка в правилната посока.

как да стартирам raspberry pi

В допълнение към стиловете за всеки компонент, обичам да имам styles папка, съдържаща глобална таблица със стилове global.scss, заедно с SASS частици, които се справят със специфична отговорност (в този случай, _fonts.scss и _variables.scss съответно за шрифтове и променливи). Глобалната таблица със стилове ни позволява да дефинираме общия вид и усещане на цялото приложение, докато помощните частици могат да бъдат импортирани от таблиците със стилове за всеки компонент, ако е необходимо.

Сега, когато общият код във всеки клон е проучен задълбочено, нека преместим фокуса си към първия подход за изпълнение на задачи / пакетиране.

Gulp + Browserify Setup

gulpfile.js

Това излиза до изненадващо голям gulpfile, с 22 вноса и 150 реда код. Така че, за краткост, ще прегледам само js, css, server, watch и default задачи в детайли.

JS пакет

// Browserify specific configuration const b = browserify({ entries: [config.paths.entry], debug: true, plugin: PROD ? [] : [hmr, watchify], cache: {}, packageCache: {} }) .transform('babelify'); b.on('update', bundle); b.on('log', gutil.log); (...) gulp.task('js', bundle); (...) // Bundles our JS using Browserify. Sourcemaps are used in development, while minification is used in production. function bundle() { return b.bundle() .on('error', gutil.log.bind(gutil, 'Browserify Error')) .pipe(source('bundle.js')) .pipe(buffer()) .pipe(cond(PROD, minifyJS())) .pipe(cond(!PROD, sourcemaps.init({loadMaps: true}))) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)); }

Този подход е доста грозен поради редица причини. От една страна, задачата е разделена на три отделни части. Първо, вие създавате вашия Browserify пакет обект b, като подавате някои опции и дефинирате някои манипулатори на събития. Тогава имате самата задача Gulp, която трябва да предаде имена като функция за обратно извикване, вместо да я вгражда (тъй като b.on('update') използва същия този обратен разговор). Това едва ли притежава елегантността на задачата за Gulp, при която просто преминавате в gulp.src и внесете някои промени.

Друг е въпросът, че това ни принуждава да имаме различни подходи за презареждане html, css и js в браузъра. Гледайки нашия Gulp watch задача:

gulp.task('watch', () => { livereload.listen({basePath: 'dist'}); gulp.watch(config.paths.html, ['html']); gulp.watch(config.paths.css, ['css']); gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); });

Когато се промени HTML файл, html задачата се изпълнява отново.

gulp.task('html', () => { return gulp.src(config.paths.html) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); });

Последните извикващи тръби livereload() ако NODE_ENV не е production, което задейства опресняване в браузъра.

Същата логика се използва и за часовника CSS. Когато се промени CSS файл, css задачата се изпълнява отново и последната тръба в css тригери на задачи livereload() и опреснява браузъра.

Обаче js watch не извиква js задача изобщо. Вместо това, манипулаторът на събития на Browserify b.on('update', bundle) обработва презареждането, използвайки съвсем различен подход (а именно, подмяна на горещ модул). Непоследователността в този подход е дразнеща, но за съжаление е необходима, за да се получи постепенно изгражда. Ако наивно просто извикахме livereload() в края на bundle функция, това би пресъздало цял JS пакет за всяка отделна промяна на JS файл. Подобен подход очевидно не се мащабира. Колкото повече JS файлове имате, толкова по-дълго отнема всяко отделяне. Изведнъж вашите 500 ms ребундове започват да отнемат 30 секунди, което наистина възпрепятства пъргавото развитие.

CSS пакет

gulp.task('css', () => { return gulp.src( [ 'node_modules/bootstrap/dist/css/bootstrap.css', 'node_modules/font-awesome/css/font-awesome.css', config.paths.css ] ) .pipe(cond(!PROD, sourcemaps.init())) .pipe(sass().on('error', sass.logError)) .pipe(concat('bundle.css')) .pipe(cond(PROD, minifyCSS())) .pipe(cond(!PROD, sourcemaps.write())) .pipe(gulp.dest(config.paths.baseDir)) .pipe(cond(!PROD, livereload())); });

Първият въпрос тук е тромавото включване на CSS на доставчика. Всеки път, когато към проекта се добавя CSS файл на нов доставчик, трябва да не забравяме да променим нашия gulpfile, за да добавим елемент към gulp.src масив, вместо да добавяме импорта на съответно място в нашия действителен изходен код.

Другият основен въпрос е извитата логика във всяка тръба. Трябваше да добавя NPM библиотека, наречена gulp-cond просто за настройка на условна логика в моите тръби и крайният резултат не е много четлив (тройни скоби навсякъде!).

Задача на сървъра

gulp.task('server', () => { nodemon({ script: 'server.js' }); });

Тази задача е много ясна. По същество е обвивка около извикването на командния ред nodemon server.js, която изпълнява server.js в среда на възел. nodemon се използва вместо node така че всякакви промени във файла да го рестартират. По подразбиране, nodemon ще рестартира текущия процес на всякакви Промяна на JS файл, поради което е важно да включите nodemon.json файл за ограничаване на обхвата му:

{ 'watch': 'server.js' }

Нека да прегледаме кода на нашия сървър.

server.js

const baseDir = process.env.NODE_ENV === 'production' ? 'build' : 'dist'; const port = process.env.NODE_ENV === 'production' ? 8080: 3000; const app = express();

Това задава основната директория на сървъра и порта на базата на средата на възела и създава екземпляр на express.

app.use(require('connect-livereload')({port: 35729})); app.use(express.static(path.join(__dirname, baseDir)));

Това добавя connect-livereload междинен софтуер (необходим за нашата настройка за презареждане на живо) и статичен междинен софтуер (необходим за обработка на нашите статични активи).

app.get('/api/sample-route', (req, res) => { res.send({ website: 'ApeeScape', blogPost: true }); });

Това е просто прост API път. Ако отидете до localhost:3000/api/sample-route в браузъра ще видите:

{ website: 'ApeeScape', blogPost: true }

В истински бекенд ще имате цяла папка, посветена на API маршрути, отделни файлове за установяване на DB връзки и т.н. Този примерен маршрут беше просто включен, за да покаже, че можем лесно да изградим бекенд на върха на интерфейса, който сме настроили.

app.get('*', (req, res) => { res.sendFile(path.join(__dirname, './', baseDir ,'/index.html')); });

Това е общ маршрут, което означава, че без значение какъв URL въведете в браузъра, сървърът ще върне нашия самотен index.html страница. Тогава отговорността на React Router е да разреши нашите маршрути от страна на клиента.

app.listen(port, () => { open(`http://localhost:${port}`); });

Това казва на нашия експресен екземпляр да изслуша посочения от нас порт и да отвори браузъра в нов раздел на посочения URL адрес.

Засега единственото нещо, което не ми харесва в настройката на сървъра, е:

app.use(require('connect-livereload')({port: 35729}));

Като се има предвид, че вече използваме gulp-livereload в нашия gulpfile това прави две отделни места, където трябва да се използва livereload.

Сега, не на последно място:

Задача по подразбиране

gulp.task('default', (cb) => { runSequence('clean', 'lint', 'test', 'html', 'css', 'js', 'fonts', 'server', 'watch', cb); });

Това е задачата, която се изпълнява, когато просто напишете gulp в терминала. Странността е необходимостта да се използва runSequence за да накарате задачите да се изпълняват последователно. Обикновено масив от задачи се изпълняват паралелно, но това не винаги е желаното поведение. Например трябва да имаме clean задачата се изпълнява преди html за да сме сигурни, че нашите целеви папки са празни, преди да преместите файлове в тях. Когато gulp 4 бъде пуснат, той ще поддържа gulp.series и gulp.parallel методи, но засега трябва да напуснем с тази малка странност в нашата настройка.

Освен това, това всъщност е доста елегантно. Цялото създаване и хостинг на нашето приложение се извършва с една команда и разбирането на която и да е част от работния процес е толкова просто, колкото изследването на отделна задача в последователността на изпълнението. Освен това можем да разделим цялата последователност на по-малки парчета за по-подробен подход при създаването и хостването на приложението. Например, бихме могли да настроим отделна задача, наречена validate който изпълнява lint и test задачи. Или може да имаме host задача, която се изпълнява server и watch. Тази способност за организиране на задачи е много мощна, особено когато приложението ви се мащабира и изисква по-автоматизирани задачи.

Разработка срещу производство

if (argv.prod) { process.env.NODE_ENV = 'production'; } let PROD = process.env.NODE_ENV === 'production';

Използване на yargs NPM библиотека, можем да предоставим флагове на командния ред на Gulp. Тук инструктирам gulpfile да настрои средата на възела на производствена, ако --prod се предава на gulp в терминала. Нашите PROD След това променливата се използва като условие за диференциране на поведението за разработка и производство в нашия gulpfile. Например една от опциите, които предаваме на нашите browserify config е:

plugin: PROD ? [] : [hmr, watchify]

Това казва browserify да не използвате никакви приставки в производствен режим и използвайте hmr и watchify плъгини в други среди.

Това PROD conditional е много полезен, защото ни спестява от необходимостта да напишем отделен gulpfile за производство и разработка, който в крайна сметка ще съдържа много повторения на кода. Вместо това можем да правим неща като gulp --prod за да стартирате задачата по подразбиране в производството или gulp html --prod за да стартирате само html задача в производството. От друга страна, видяхме по-рано, че затрупваме нашите тръбопроводи за Gulp с изявления като .pipe(cond(!PROD, livereload())) не са най-четливите. В крайна сметка е въпрос на предпочитание дали искате да използвате подхода на булевата променлива или да настроите две отделни gulpfiles.

Сега нека да видим какво се случва, когато продължаваме да използваме Gulp като наш бегач на задачи, но заменим Browserify с Webpack.

Тестването на прототипа на мобилно приложение може да се направи ръчно или какво?

Настройка на Gulp + Webpack

Изведнъж нашият gulpfile е дълъг само 99 реда с 12 импорта, което е значително намаление от предишната ни настройка! Ако проверим задачата по подразбиране:

gulp.task('default', (cb) => { runSequence('lint', 'test', 'build', 'server', 'watch', cb); });

Сега нашата пълна настройка на уеб приложение изисква само пет задачи вместо девет, драматично подобрение.

Освен това премахнахме необходимостта от livereload. Нашите watch задачата сега е просто:

gulp.task('watch', () => { gulp.watch(config.paths.js, () => { runSequence('lint', 'test'); }); });

Това означава, че нашият наблюдател на глътка не задейства какъвто и да е вид поведение на възстановяване. Като допълнителен бонус не е необходимо да прехвърляме index.html от app до dist или build вече.

Връщайки фокуса си към намаляването на задачата, нашите html, css, js и fonts всички задачи са заменени с един build задача:

gulp.task('build', () => { runSequence('clean', 'html'); return gulp.src(config.paths.entry) .pipe(webpack(require('./webpack.config'))) .pipe(gulp.dest(config.paths.baseDir)); });

Достатъчно просто. Изпълнете clean и html задачи в последователност. След като приключите, вземете нашата входна точка, прекарайте я през Webpack, като подавате webpack.config.js файл, за да го конфигурирате, и изпратете получения пакет на нашия baseDir (или dist или build, в зависимост от възела env).

Нека да разгледаме конфигурационния файл на Webpack:

webpack.config.js

Това е доста голям и плашещ конфигурационен файл, така че нека да обясним някои от важните свойства, зададени в нашия module.exports обект.

devtool: PROD ? 'source-map' : 'eval-source-map',

Това задава типа на изходните карти, които Webpack ще използва. Webpack не само поддържа изходни карти от кутията, но всъщност поддържа широк спектър от опции за изходни карти. Всяка опция осигурява различен баланс на детайлите на картата на източника спрямо скоростта на възстановяване (времето, необходимо за възстановяване на промените). Това означава, че можем да използваме „евтина“ опция за източник на карта за разработка, за да постигнем бързо презареждане и по-скъпа опция за източник на карта в производството.

entry: PROD ? './app/index' : [ 'webpack-hot-middleware/client?reload=true', // reloads the page if hot module reloading fails. './app/index' ]

Това е нашата входна точка за пакета. Забележете, че е предаден масив, което означава, че е възможно да има множество входни точки. В този случай имаме очакваната точка за влизане app/index.js както и webpack-hot-middleware входна точка, която се използва като част от нашата настройка за презареждане на горещ модул.

output: { path: PROD ? __dirname + '/build' : __dirname + '/dist', publicPath: '/', filename: 'bundle.js' },

Тук ще бъде изведен компилираният пакет. Най-объркващата опция е publicPath. Той задава основния URL адрес за това къде вашият пакет ще бъде хостван на сървъра. Така например, ако вашият publicPath е /public/assets, тогава пакетът ще се появи под /public/assets/bundle.js на сървъра.

devServer: { contentBase: PROD ? './build' : './app' }

Това казва на сървъра коя папка във вашия проект да използва като основна директория на сървъра.

Ако някога се объркате как Webpack картографира създадения пакет във вашия проект към пакета на сървъра, просто запомнете следното:

  • path + filename: Точното местоположение на пакета в изходния код на вашия проект
  • contentBase (като корен, /) + publicPath: Местоположението на пакета на сървъра
plugins: PROD ? [ new webpack.optimize.OccurenceOrderPlugin(), new webpack.DefinePlugin(GLOBALS), new ExtractTextPlugin('bundle.css'), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}) ] : [ new webpack.HotModuleReplacementPlugin(), new webpack.NoErrorsPlugin() ],

Това са приставки, които подобряват по някакъв начин функционалността на Webpack. Например, webpack.optimize.UglifyJsPlugin отговаря за минификацията.

loaders: [ {test: /.js$/, include: path.join(__dirname, 'app'), loaders: ['babel']}, { test: /.css$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap'): 'style!css?sourceMap' }, { test: /.scss$/, loader: PROD ? ExtractTextPlugin.extract('style', 'css?sourceMap!resolve-url!sass?sourceMap') : 'style!css?sourceMap!resolve-url!sass?sourceMap' }, gif)(?S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]', woff2 ]

Това са товарачи. По същество те предварително обработват файлове, които се зареждат чрез require() изявления. Те донякъде приличат на тръби Gulp, тъй като можете да свързвате товарачите заедно.

Нека разгледаме един от нашите обекти за зареждане:

{test: /.scss$/, loader: 'style!css?sourceMap!resolve-url!sass?sourceMap'}

test свойството казва на Webpack, че даденият зареждащ файл се прилага, ако файл съвпада с предоставения модел на регулярно изражение, в този случай /.scss$/ loader свойството съответства на действието, което изпълнява товарачът. Тук ние веригираме заедно style, css, resolve-url и sass товарачи, които се изпълняват в обратен ред.

Трябва да призная, че не намирам loader3!loader2!loader1 синтаксис много елегантен. В крайна сметка кога някога трябва да четете нещо в програма отдясно наляво? Въпреки това, товарачите са много мощна характеристика на webpack. Всъщност, току-що споменатият товарач ни позволява да импортираме SASS файлове директно в нашия JavaScript! Например, можем да импортираме нашите доставчици и глобални таблици със стилове в нашия файл с входна точка:

index.js

import React from 'react'; import {render} from 'react-dom'; import {Router, browserHistory} from 'react-router'; import routes from './routes'; // CSS imports import '../node_modules/bootstrap/dist/css/bootstrap.css'; import '../node_modules/font-awesome/css/font-awesome.css'; import './styles/global.scss'; render(, document.getElementById('app'));

По същия начин в нашия компонент Header можем да добавим import './Header.scss' за да импортирате свързаната таблица със стилове на компонента. Това важи и за всички наши други компоненти.

Според мен това почти може да се счита за революционна промяна в света на разработката на JavaScript. Няма нужда да се притеснявате за CSS групиране, минимизиране или източници, тъй като нашият товарач обработва всичко това вместо нас. Дори презареждането на горещи модули работи за нашите CSS файлове. Тогава възможността за обработка на импортиране на JS и CSS в един и същ файл прави концептуално по-просто разработване: Повече последователност, по-малко превключване на контекста и по-лесно разсъждение.

За да дадем кратко резюме на това как работи тази функция: Webpack поставя CSS в нашия JS пакет. Всъщност Webpack може да направи това и за изображения и шрифтове:

gif)(?S*)?$/, loader: 'url?limit=100000&name=img/[name].[ext]', ttf)(?S*)?$/, loader: 'url?limit=100000&name=fonts/[name].[ext]'

Зареждащият URL адрес инструктира Webpack да вгради нашите изображения и шрифтове като URL адреси за данни, ако те са под 100 KB, в противен случай ги обслужва като отделни файлове. Разбира се, можем също да конфигурираме размера на границата на различна стойност като 10 KB.

И това е конфигурацията на Webpack накратко. Ще призная, че има доста голям брой настройки, но ползите от използването му са просто феноменални. Въпреки че Browserify има приставки и преобразувания, те просто не могат да се сравняват с Webpack товарачите по отношение на добавената функционалност.

Настройка на Webpack + NPM скриптове

В тази настройка използваме директно npm скриптове, вместо да разчитаме на gulpfile за автоматизиране на нашите задачи.

package.json

'scripts': { 'start': 'npm-run-all --parallel lint:watch test:watch build', 'start:prod': 'npm-run-all --parallel lint test build:prod', 'clean-dist': 'rimraf ./dist && mkdir dist', 'clean-build': 'rimraf ./build && mkdir build', 'clean': 'npm-run-all clean-dist clean-build', 'test': 'mocha ./app/**/*.test.js --compilers js:babel-core/register', 'test:watch': 'npm run test -- --watch', 'lint': 'esw ./app/**/*.js', 'lint:watch': 'npm run lint -- --watch', 'server': 'nodemon server.js', 'server:prod': 'cross-env NODE_ENV=production nodemon server.js', 'build-html': 'node tools/buildHtml.js', 'build-html:prod': 'cross-env NODE_ENV=production node tools/buildHtml.js', 'prebuild': 'npm-run-all clean-dist build-html', 'build': 'webpack', 'postbuild': 'npm run server', 'prebuild:prod': 'npm-run-all clean-build build-html:prod', 'build:prod': 'cross-env NODE_ENV=production webpack', 'postbuild:prod': 'npm run server:prod' }

За да стартирате компилации за разработка и производство, въведете npm start и npm run start:prod, съответно.

Това със сигурност е по-компактно от нашия gulpfile, като се има предвид, че сме изрязали от 99 до 150 реда код до 19 NPM скрипта или 12, ако изключим производствените скриптове (повечето от които просто отразяват скриптовете за разработка с възловата среда, настроена на продукция ). Недостатъкът е, че тези команди са малко загадъчни в сравнение с нашите аналози на Gulp и не са толкова изразителни. Например, няма начин (поне за който знам) един скрипт npm да изпълнява определени команди последователно, а други паралелно. Това е или едното, или другото.

Този подход обаче има огромно предимство. Чрез използване на NPM библиотеки като mocha директно от командния ред, не е необходимо да инсталирате еквивалентна обвивка на Gulp за всяка (в този случай gulp-mocha).

Вместо NPM инсталиране

байпас кредитна карта за проверка на възрастта
  • муха-еслинт
  • глътка-мока
  • глътка-нодемон
  • и т.н.

Инсталираме следните пакети:

  • прашка
  • мока
  • нодемон
  • и т.н.

Цитирайки публикацията на Кори Хаус, Защо оставих глътка и мрънкане за NPM скриптове :

Бях голям фен на Гълп. Но при последния ми проект завърших със стотици редове в моя gulpfile и около дузина Gulp плъгини. Бях се борил да интегрирам Webpack, Browsersync, горещо презареждане, Mocha и много други, използвайки Gulp. Защо? Е, някои плъгини имаха недостатъчна документация за моя случай на употреба. Някои приставки разкриха само част от API, от който се нуждаех. Човек имаше странна грешка, при която щеше да гледа само малък брой файлове. Друг лишен цвят при извеждане в командния ред.

Той посочва три основни проблема с Gulp:

  1. Зависимост от авторите на приставки
  2. Неприятно за отстраняване на грешки
  3. Неразграничена документация

Склонен съм да се съглася с всичко това.

1. Зависимост от авторите на приставки

Когато библиотека като eslint се актуализира, свързаните gulp-eslint библиотеката се нуждае от съответна актуализация. Ако поддръжникът на библиотеката загуби интерес, gulp версията на библиотеката не се синхронизира с родната. Същото важи и за създаването на нова библиотека. Ако някой създаде библиотека xyz и той хваща, тогава изведнъж се нуждаете от съответния gulp-xyz библиотека, за да го използвате във вашите глътка задачи.

В известен смисъл този подход просто не се мащабира. В идеалния случай бихме искали подход като Gulp, който може да използва родните библиотеки.

2. Неприятно за отстраняване на грешки

Въпреки че библиотеки като gulp-plumber помогнете за значително облекчаване на този проблем, въпреки това е вярно, че отчитането на грешки в gulp просто не е много полезно. Ако дори една тръба изхвърли необработено изключение, получавате проследяване на стека за проблем, който изглежда напълно несвързан с причината за проблема във вашия изходен код. Това може да направи отстраняването на грешки кошмар в някои случаи. Никакво търсене в Google или Stack Overflow наистина не може да ви помогне, ако грешката е достатъчно загадъчна или подвеждаща.

3. Разединена документация

Често намирам, че това е малко gulp библиотеките са склонни да имат много ограничена документация. Подозирам, че това е така, защото авторът обикновено прави библиотеката предимно за собствена употреба. Освен това е обичайно да се търси документация както за приставката Gulp, така и за самата родна библиотека, което означава много превключване на контекста и два пъти повече четене.

Заключение

Изглежда ми доста ясно, че Webpack е за предпочитане пред Browserify и NPM скриптовете са за предпочитане пред Gulp, въпреки че всяка опция има своите предимства и недостатъци. Gulp със сигурност е по-изразителен и удобен за използване от NPM скриптовете, но вие плащате цената във всички добавени абстракции.

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

Свързани:
  • Поддържайте контрол: Ръководство за Webpack and React, Pt. 1
  • Gulp Under the Hood: Изграждане на инструмент за автоматизация на задачи, базиран на поток

Скочи в VR / AR дизайн

Ux Дизайн

Скочи в VR / AR дизайн
Автоматизация навсякъде и ApeeScape довеждат автоматизацията при поискване до глобалната работна сила

Автоматизация навсякъде и ApeeScape довеждат автоматизацията при поискване до глобалната работна сила

Други

Популярни Публикации
Урок за скриптове на Google Apps за овладяване на макроси
Урок за скриптове на Google Apps за овладяване на макроси
Теория на цветовете за дизайнери - Crash Course (с инфографика)
Теория на цветовете за дизайнери - Crash Course (с инфографика)
ApeeScape стартира нова специализация DevOps по заявка за обслужване на Enterprise Shift към облака
ApeeScape стартира нова специализация DevOps по заявка за обслужване на Enterprise Shift към облака
Нула до герой: Рецепти за производство на колби
Нула до герой: Рецепти за производство на колби
Как да проведем успешна техническа конференция: Събитието в CordobaJS
Как да проведем успешна техническа конференция: Събитието в CordobaJS
 
Как да накараме отдалечената работа да работи за вас
Как да накараме отдалечената работа да работи за вас
Всеки продукт има теза
Всеки продукт има теза
Комодитизирани смартфони: Привеждане на 4G в развиващите се страни
Комодитизирани смартфони: Привеждане на 4G в развиващите се страни
Запознайте се с Volt, обещаваща Ruby рамка за динамични приложения
Запознайте се с Volt, обещаваща Ruby рамка за динамични приложения
Разширени тактики за силно съвместни, отдалечени екипи
Разширени тактики за силно съвместни, отдалечени екипи
Популярни Публикации
  • как да използвате powerpivot в excel 2016
  • как да използвам flexbox в css
  • прилики между партньорство и корпорация
  • как да си направим google стъкло
  • различни видове корпорации llc
Категории
  • Agile Talent
  • Растеж На Приходите
  • Мобилен Дизайн
  • Управление На Проекти
  • © 2022 | Всички Права Запазени

    portaldacalheta.pt