ReactJs початок.

ReactJs початок. Робоче оточення.

Швидкий старт проекту (скафолдінг).

npx create-react-app my-app --template typescript

Запуск сервера

npm run start

Складання.

npm run build

Складання з відстеження змін

npm install npm-watch --save

Додаємо до package.json

...
"watch": {
    "build": {
      "patterns": [
        "src"
      ],
      "extensions": "js,jsx"
    }
  },
  "scripts": {
    "watch": "npm-watch",

  ....

Запуск.

npm run watch

Ставимо реакт у ручну.

npm install react react-dom --save
npm install @types/react --save

Перейменуємо index.ts на index.tsx

Додамо опцію jsx у tsconfig.json

{
    "compilerOptions": {
        "module": "commonjs",
        "target": "ES5",
        "outDir": "dist",
        "rootDir": "src",
        "esModuleInterop": true,
        "jsx": "react"
    },
    "exclude": [
        "node_modules"
    ]
}

Створимо найпростіший компонент src/client/index.tsx.

import * as React from "react";
import * as ReactDOM from 'react-dom';

function App() {
    return (
      <h1>Hello from react!</h1>
    );
}

ReactDOM.render(
    <App />,
    document.getElementById('react-app')
  );

Установка SystemJs

npm install systemjs@0.19.22 --save

Підключаємо у завантажувачі.

<!DOCTYPE html>
<html>
    <head><title>TypeScript Greeter</title>
        <script src="node_modules/systemjs/dist/system.js"></script>

    </head>
    <body>
       <div id="react-app"></div>
      <script>
            SystemJS.config({
                defaultJSExtensions: true,
                map: {
                    'react': 'node_modules/react/umd',
                    'react-dom': 'node_modules/react-dom/umd'
                },
                packages: {
                    'react': {
                        main: './react.development.js'
                    },
                    'react-dom': {
                        main: './react-dom.development.js'
                    }
                }
            });
            SystemJS.import('dist/client/index.js');           
      </script>
    </body>
</html>

Використання збирача замість SystemJs.

Встановлюємо gulp.

npm install --save gulp

Робимо просте завдання у файлі gulp.j

var gulp = require('gulp');
gulp.task('default', () => {
    console.log('Gulp task!!');
})

Запуск.

node node_modules/gulp/bin/gulp.js

Оскільки процес асинхронний ми маємо повернути подію завершення

var gulp = require('gulp');
gulp.task('default', (done) => {
    console.log('Gulp task!!');
    done();
})

Встановимо компілятор gulp-typescript

 npm install --save gulp-typescript
 npm install --save browserify

Відкомпілюємо в папку dist/prod

var gulp = require('gulp');
var browserify = require('browserify');
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
gulp.task('default', (done) => {
    return tsProject.src()
        .pipe(tsProject())
        .js.pipe(gulp.dest("dist/prod"));

})

Тепер нам потрібно зібрати всі модулі в один файл.

Спочатку встановимо browserify, tsify, і vinyl-source-stream. tsify це плагін для Browserify, який, подібно до gulp-typescript, надає доступ до компілятора TypeScript. vinyl-source-stream дозволяє узгодити файловий висновок Browserify та формат під назвою vinyl, який розуміє gulp.

npm install --save-dev browserify tsify vinyl-source-stream

Скрипт складання.

var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');
var tsify = require("tsify");

gulp.task('default', (done) => {
    return browserify({
        basedir: './src/client',
        debug: true,
        entries: ['index.tsx']
    })
    .plugin(tsify)
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(gulp.dest("dist/prod"));

})

Тепер можна включити наш бандл до сторінки одним файлом та прибрати SystemJs.

<script src="dist/prod/bundle.js"></script>

bundle вийшов близько 4.1 мегабайт.

Спробуймо агліфікувати (обфуркація).

Устоанівка

npm install gulp-uglify --save
npm install vinyl-buffer --save

Застосування.. … var uglify = require(‘gulp-uglify’); var buffer = require(‘vinyl-buffer’);

gulp.task('default', (done) => {
    return browserify({
        basedir: './src/client',
        debug: true,
        entries: ['index.tsx']
    })
    .plugin(tsify)
    .bundle()
    .pipe(source('bundle.js'))
    .pipe(buffer())
    .pipe(uglify())
    .pipe(gulp.dest("dist/prod"));

})

Отримуємо помилку.

start page

Виявляється uglify не підтримує es6.

Ставимо той, що підтримує.

npm i gulp-uglify-es --save

Змінюємо скрипт.

var uglify = require('gulp-uglify-es').default;

start page

Тепер bundle.js зменшився до 1.4 мб.

Обробка CSS вимагає ще однієї бібліотеки.

npm install --save css-modulesify

Застосування.

var cssModulesify = require('css-modulesify');
....
gulp.task('default', (done) => {
    return browserify(...)
    .plugin(cssModulesify, {
        rootDir: __dirname,
        output: './dist/main.css',
        generateScopedName: cssModulesify.generateShortName
      })
    ...

Відстеження змін за допомогою nodemon.

sudo npm install -g nodemon

Команда для запуску.

nodemon node_modules/gulp/bin/gulp.js -e tsx

Видалення білду перед перестворенням.

Встановлюємо бібліотеку.

npm install --save-dev del

Використання.

var del = require('del');

gulp.task('default', (done) => {
    del(['../app/static/js/app/**'],{force: true});

Спробуємо ще зменшити компресором gzip

npm i compression --save

Вставляємо код сервера.

const compression = require('compression');
app.use(compression())

За підсумком отримали.

start page

340 кб - непогано, враховуючи, що це все разом із бібліотекою React.

Тепер розберемося як копіювати index.html у складання.

Створимо html для продакшина, який використовує бандл src/server/tpl/index_prod.html.

<!DOCTYPE html>
<html>
    <head>
      <title>Production</title>
    </head>
    <body>
       <div id="react-app"></div>
      <script src="dist/prod/bundle.js"></script>
    </body>
</html>

Т.к. ми копіюватимемо з іншим ім’ям встановимо бібліотеку для цього.

npm i gulp-rename --save

Скопіюємо index_prod.html як index.html при складанні в каталог dist.

Зробимо це в окремому завданні

rename = require('gulp-rename'),
gulp.task("copy-html", function () {
    return gulp.src('./src/server/tpl/index_prod.html')
        .pipe(rename('index.html'))
        .pipe(gulp.dest("dist/prod"));
});

Запускаємо

start page

Тепер включимо це завдання до основного складання.

Комбінування завдань.

gulp.task("copy-html", function () {
   ...
});


gulp.task('build-app', (done) => {
    ...
})

gulp.task('default', gulp.series('copy-html', 'build-app'));