ExpressでテンプレートエンジンPugを利用してみる

今回はExpresspugを使ってみようと思います。

まずプロジェクトディレクトリを作成してください。

mkdir express_practice

その後、npm init -y

package.jsonが作成されます。

その後expressをインストールします。

npm i -D express

今回はpugを使用するので

npm i -D pug

viewフォルダにindex.pugファイルを用意します。

html
  head
    title!= title
  body
    h1!= message

プロジェクトフォルダ配下にapp.jsファイルを追加します。

const express = require('express');
const app = express();
app.set('view engine', 'pug');

const recordLog = function (req, res, next) {
  console.log('localhost:3000にアクセスしました');
  next();
};

app.use(recordLog);

app.get('/', function (req, res) {
  res.render('index', { title: 'Hello', message: 'Express'});
});


app.listen(3000);

res.render('index', { title: 'Hey', message: 'Hello there!'});

↑ではindex.pugで設定した変数に値がそれぞれ入ります。

その後、node app.jsと実行後、ブラウザでlocalhost:3000にアクセスしてみてください。

f:id:top_men:20180318002323p:plain

このように表示されればOKです!

簡単ではありますが以上になります。

今後はmysqlを使ってデータのやりとりをしてみようと思います。

ReactのFragmentsって便利

今回はReactの開発において今後積極的に使っていこうと思ったものを紹介したいと思います!

タイトルにも書いてある通り、Fragmentsです。

言葉で説明するよりも下記のコードを見た方が理解し易いです。

import * as React from "react";

class Columns extends React.Component {
  render() {
    return (
      <div>
        <td>データ1</td>
        <td>データ2</td>
      </div>
    );
  }
}

ここで<td>タグのリストをレンダリングしたいのに余計なノードをDOMに追加しなけばいけません。階層が余計に深くなったりルートの要素に余分なスタイルを当てなければいけない時などが出てくる可能性があります。

もやもやしますよね・・・

React v16 からはこの忌まわしき問題から解放されます!!

新たにFragmentを読み込みます。

このように書くことで上記の問題を回避することができるのです!簡単ですね!

import React, { Fragment } from 'react'

class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>データ1</td>
        <td>データ2</td>
      </React.Fragment>
    );
  }
}

レンダリングされた結果がこちらになります。

<td>データ1</td>
<td>データ2</td>

また別の記述の仕方があります。

import React, { Fragment } from 'react'

class Columns extends React.Component {
  render() {
    return (
      <>
        <td>データ1</td>
        <td>データ2</td>
      </>
    );
  }
}

こちらの書き方はまだサポート他のツールでサポートされていないようなので<React.Fragment>を使用することが推奨されています。

簡単ではありますが、是非活用してみてください!

ES2015でポップアップのテンプレートを作ってみた!

今回はJavaScriptで簡単なポップアップのテンプレートを作ってみたのでサンプルコードを載せておきます。

<!DOCTYPE html>
<html lang='ja'>
<head>
   <meta charset='UTF-8'>
   <meta name='viewport' content='width=device-width, initial-scale=1.0'>
   <meta http-equiv='X-UA-Compatible' content='ie=edge'>
   <title>ポップアップのサンプル</title>
   <link rel='stylesheet' href='css/style.css'>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.26.0/babel.min.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js"></script>
</head>
<body>
    <button class="popupButton" id="js-clickEl">クリックする要素</button>
    <div class='popup' id="js-popup">
        <div class='popup_content'>
            <p class='popup_content_closeButton' id="js-popupCloseButton">X</p>
            <div class='popup_content_description'>何か文言が入ります</div>
        <div>
    </div>
    <script src="js/Popup.js"></script>
</body>
</html>
.popupButton {
    border: none;
    background: #323232;
    color: #fff;
    padding: 20px;
    border-radius: 33px;
    cursor: pointer;
}
.popup {
    width: 100%;
    height: 100%;
    position: fixed;
    top: 0;
    left: 0;
    background: rgba(5,5,5,0.8);
    opacity: 0;
    transition:all .3s;
    transform: scale(0);
}

.popup.is-active {
    transform: scale(1);
    opacity: 1;
}

.popup_content {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background: #fff;
    width: 400px;
    height: 360px;
    padding: 30px;
}

.popup_content_closeButton {
    cursor: pointer;
    text-align: right;
}

.popup_content_description {
    margin-top: 30px;
}
class PopUp {
    constructor(clickEl, popupEl, closeEl){
        this.clickEl = document.getElementById(clickEl)
        this.popupEl = document.getElementById(popupEl)
        this.closeEl = document.getElementById(closeEl)
    }
    setEventListener(){
        this.clickEl.addEventListener("click", this.displayPopup.bind(this));
        this.closeEl.addEventListener("click", this.closePopup.bind(this));
    }
    displayPopup(){
    this.popupEl.classList.add("is-active")
    }
    closePopup(){
        this.popupEl.classList.remove("is-active")
    }
}
const simplePopup = new PopUp('js-clickEl', "js-popup", "js-popupCloseButton");
simplePopup.setEventListener();

このPopupクラスを使って初期化した後の引数に対象となる要素のIDを入れればデザインの違うポップアップにも対応できます!

是非使ってみてください!

React+TypeScript+Webpackで環境構築

今回はReact+TypeScript+webpackの環境構築をしていきたいと思います。公式のドキュメントを参考になぞってみました。是非、一読してみてください。

前提としてnodenpmはインストール済みで進めていきます。

作業ディレクトリを作成してください。

以下のディレクトリ構成で進めていきます。

proj/
├─ dist/
└─ src/
   └─ components/

ここでは、まだdistフォルダを作成しなくても良いです。 後述しますが、webpackが自動で作ってくれます。

プロジェクトディレクトリ直下でnpm init -yと実行してください。 そうするとpackage.jsonが生成されます。

webpackのインストール

まずグローバルにwebpackがインストールされているか確認してください。 まだインストールがされていなければ

npm i -g webpackと実行してwebpackがインストールされていることを確認してください。

Reactのインストール

reactとreact-domをインストールしましょう。

npm i -D react react-dom @types/react @types/react-dom

ここで@typesという接頭辞が出てきて何ぞや?と思われた方もいると思います。この@typesというのはreactreact-dom型定義ファイルになります。

どんな型定義ファイルがあるかはこちらから確認ができます。

react単体で型定義をする場合は、PropTypesなどを作成すると思いますが、TypeScript 2から型定義ファイルの管理をnpmで行えるようになりました。

TypeScriptのインストール

npm install --save-dev typescript awesome-typescript-loader source-map-loader

この中のパッケージのawesome-typescript-loadersource-map-loaderはwebpackと一緒に使うときに必要になります。

awesome-typescript-loaderはwebpackがTypeScriptのスタンダードな設定ファイルであるtsconfig.jsonを使ってtypescriptのファイルをコンパイルしてくれます。

source-map-loaderはその名の通り、ソースマップを生成してくれます。

tsconfig.jsonの設定

tsconfig.jsonファイルをプロジェクトディレクトリ直下に作成し、以下のように設定してください。

{
  "compilerOptions": {
    "outDir": "./dist/",
    "sourceMap": true,
    "noImplicitAny": true,
    "module": "commonjs",
    "target": "es5",
    "jsx": "react"
  },
  "include": [
    "./src/**/*"
  ]
}
  • outDir

  • sourceMap

    • ソースマップの有無。
  • noImplicitAny

    • 厳密に型を決めるときなど、暗黙のanyの型はエラーとすることができます。
  • module

    • moduleコードの生成方法
  • target

    • トランスパイルする先の、ECMAScript の ターゲット・バージョンになります.。

詳細を知りたい方はこちらで確認してください。

Let's Write Code

実際にReactを使ってTypeScriptを書いていきましょう。 まず、Hello.tsxというファイルをsrc/components直下に配置してください。

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

export const Hello = (props: HelloProps) => <h1>Hello from {props.compiler} and {props.framework}!</h1>;

こちらはステートレスコンポーネントで記述しています。 文字通り、何か状態を保持ている状態ではなく、描画するためだけのコンポーネントになります。

クラス構文を使って記述すると以下のようになります。

import * as React from "react";

export interface HelloProps { compiler: string; framework: string; }

// 'HelloProps' describes the shape of props.
// State is never set so we use the '{}' type.
export class Hello extends React.Component<HelloProps, {}> {
    render() {
        return <h1>Hello from {this.props.compiler} and {this.props.framework}!</h1>;
    }
}

コードの中にこのような記述があります。

React.Component<HelloProps, {}>

ComponentはReact.Component<P, S> を extends したクラスを作成します。 Pは props の型、 Sは state の型となります。

次にindex.tsxをsrc直下に追加します。

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

import { Hello } from "./components/Hello";

ReactDOM.render(
    <Hello compiler="TypeScript" framework="React" />,
    document.getElementById("example")
);

ここでは単純にindex.tsxHello.tsxをインポートしてReact.DOMのrederメソッドでレンダリングしています。

次にHello.tsxの内容を表示させるためにindex.htmlファイルを作成します。

プロジェクトフォルダ直下にindex.htmlを作成してください。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>Hello React!</title>
    </head>
    <body>
        <div id="example"></div>

        <!-- Dependencies -->
        <script src="./node_modules/react/umd/react.development.js"></script>
        <script src="./node_modules/react-dom/umd/react-dom.development.js"></script>

        <!-- Main -->
        <script src="./dist/bundle.js"></script>
    </body>
</html>

webpackの設定ファイルを作成

プロジェクトディレクトリの直下にwebpack.config.jsファイルを作成してください。

module.exports = {
    entry: "./src/index.tsx",
    output: {
        filename: "bundle.js",
        path: __dirname + "/dist"
    },

    // Enable sourcemaps for debugging webpack's output.
    devtool: "source-map",

    resolve: {
        // Add '.ts' and '.tsx' as resolvable extensions.
        extensions: [".ts", ".tsx", ".js", ".json"]
    },

    module: {
        rules: [
            // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
            { test: /\.tsx?$/, loader: "awesome-typescript-loader" },

            // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
            { enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
        ]
    },

    // When importing a module whose path matches one of the following, just
    // assume a corresponding global variable exists and use that instead.
    // This is important because it allows us to avoid bundling all of our
    // dependencies, which allows browsers to cache those libraries between builds.
    externals: {
        "react": "React",
        "react-dom": "ReactDOM"
    },
};

上記externalsとあると思いますが、React.jsのプロジェクトでは、webpackによるビルド時のデフォルト挙動がReact.jsライブラリ自体もビルドするため、時間がかかります。

そこでexternals指定してReact.jsをビルドから除外する手順が有効となります。

webapackコマンドを実行してください。

f:id:top_men:20180307010932p:plain

このように表示されていればOKです!

今度はローカルサーバーを立てながら実際に簡単なTodoアプリを作成していきたいと思います。

デザイナーでも楽々フロントエンドの環境構築「PINGY CLI」

最近、「環境構築とかしたくないー」などと嘆くデザイナーさんがいらっしゃったので、何か手軽にフロントエンドの環境を構築できる方法はないかなーと思っていました。そこで良いツールを見つけました!!

その名もPingyです。

f:id:top_men:20180301224625p:plain

gulpやGruntなどは学習コストが掛かります。

Pingyの場合は、複雑なビルドのフローなどには向きませんが、設定ファイルなどもシンプルで初心者に優しく簡単に環境構築ができます!

では、早速環境構築をしていきましょう!

nodeが入っていることは前提としていますのでまだNodeをインストールしていない方は下記の記事を参考にしてください。(尚nodeのバージョンは6以上をサポートしています)

Macユーザーはこちら

qiita.com

Windowsユーザーはこちら qiita.com

1 インストール

npm i -g @pingy/cli

作業ディレクトリを作成

mkdir pingy_practice

作業ディレクトリへ移動

cd pingy_practice

2 初期設定

作業ディレクトリへ移動したのち、下記のコマンドを実行します。

pingy init

そうすると選択形式でいろいろと聞かれますので順に答えていきましょう!

HTMLの設定

f:id:top_men:20180301233024p:plain

先ずはhtmlのテンプレートエンジンはどうするのかを問われているので今回はPugを選択

CSSの設定

f:id:top_men:20180301233219p:plain

次にcssメタ言語を問われているのでSass(.scss)を選択。

(ここでは詳しく説明しませんが、.scssと.sassは記述方法がことなるので注意してください)

JavaScriptの設定

f:id:top_men:20180301233500p:plain

ここではBabelを選択。Babelは新しいJavaScriptの記述が可能になり、ブラウザが解釈できるように旧来のJavaScriptにトランスパイルしてくれます。

すべての設定が終わったのであとはこれらのパッケージをインストールするのでYを選択しましょう。

f:id:top_men:20180301232909p:plain

その後、pingy devと入力してローカルサーバーを立てます。

そうするとこのようにタブが開き、このような画面になると思います。

f:id:top_men:20180301235137p:plain

これで開発できる状態になりました!! 簡単ですね!!!

試しにscssファイルにbodyにblueとスタイルを変更してみてください。

f:id:top_men:20180301235456p:plain

ブラウザをリロードしていないにも関わらず、スタイルの変更がされました!

scssだけでなく、pugjsもリアルタイムに変更されるので試してみてください。

ビルド

pingy.jsonがあるファイルと同じ階層の場所でpingy exportとコマンドを実行してください。

distフォルダができたと思います。ビルドも簡単ですね!

pingy.jsonファイルを少し覗いてみましょう。

f:id:top_men:20180302000803p:plain

画像にも書いてありますが

  • exportDir:ビルドした時のディレクトリ名を設定
  • minify:圧縮するかしないか
  • compaileコンパイルの有無(基本はtrue)
  • exclusions:ビルドしないディレクトリ等
  • port:ポート番号の設定

複雑なディレクトリ構成で開発をしないのであれば、Pingyが重宝すると思います。あまり開発環境構築を好まないデザイナーさんなどにも使いやすいのではないでしょうか?

その時々の状況に合わせて是非使ってみてください!!

webpack4の基礎

ついに webapck4.0.0がリリースされましたね!

f:id:top_men:20180227025935p:plain

変更点としてよく言われているのが設定ファイルが不要ということです。

この記事では主要な変更点に絞って実際に手を動かしながらwebpack4の特徴を掴んでいくことを目的とします。

では早速、開発用のディレクトリを作成します。

mkdir webpack4_practice

npm init -y

package.jsonファイルが作られます。

ではではwebpack4.0.0をインストールしましょう!

npm i -D webpack

webpackみたいにコマンドを実行している場合はcliを入れる必要があります。webpack-cliをインストールしましょう。

npm i webpack-cli -D

インストールができたらpackage.jsonを開き、以下の記述を追加します。

"scripts": {
  "build": "webpack"
}

その後以下のコマンドを実行してください!

npm run build

このようなエラー文がでると思います。 ERROR in Entry module not found: Error: Can't resolve './src' in '~/webpack4_practice'

これはどういうことかというとwebpack4が自動的に./src以下にエントリーポイントを探しにいってくれるのです。

以前のバージョンではwebpack.config.jsファイルの中でエントリーポイントと出力先を記述する必要があったと思います。

const path = require('path');

module.exports = {
  entry: {
    'index': [
      path.resolve(__dirname, 'src/index.js')
    ]
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'public'),
    publicPath: '/',
  },
};

ではでは実際にファイルを作成してビルドするところまでやってみましょう。

./src/index.jsとファイルを作成します。

console.log("This is the entry file")

その後先ほどpackage.jsonに記述したようにnpm run buildと実行してみてください。

新しく./dist/main.jsとファイルができていると思います。

しつこいようですがまだ設定ファイルは記述していません

記事の頭でも言及しましたが、webpack4での新たな機能のひとつとして

設定ファイルを必要としない

と言われています。

もう少し詳しく見ていきます。

まずはじめにwebpackではProduction用とDevelopment用で2ファイル用意するのが典型的な例でした。

これは大きなプロジェクトになればなるほど必要になってきます。

ですがwebpack4ではどうでしょうか?
webpack4では

  • productionモード
  • developmentモード

というものがあります。 実際に手を動かして見ていきましょう。

package.jsonを編集します。

"scripts": {
  "dev": "webpack --mode development",
  "build": "webpack --mode production"
}

npm run devと実行後、./dist/main.jsを見てみてください。minifyされていないことが確認できると思います。

その後npm run buildと実行し、./dist/main.jsを見てみてください。minifiedされていることが確認できるかと思います。

とても簡単な例ですが、webpack4ではこのようにそれぞれ1行のコマンドでDevelopment用とProduction用とで処理を変えることができます。とっても簡単ですね♪

次にBabelを使用してES6 → ES5のトランスパイルをしていきたいと思います。

babel-loaderがwebpackのがES6からES5にトランスパイルするためのloaderなので以下のパッケージをインストールします。

  • babel-core
  • babel-loader
  • babel-preset-env

以下のコマンドを実行します。

npm i babel-core babel-loader babel-preset-env -D

その後、 .babelrcをプロジェクトフォルダ直下に作成し、以下を記述します。

{
    "presets": [
        "env"
    ]
}

ここで疑問に思うかもしれません。 設定ファイルが不要というのがwebpack4の大きな変更点として言われているにのに、結局設定ファイルが必要になるんだなーと。

最小限の構成で開発をするのであれば、今までで紹介した

  • エントリーポイント、ビルド先がデフォルトで決まっている
  • Production、Developmentモードがコマンド一つで切り替え可能

上記のことから設定ファイルが必要がないということが言えるのではないのでしょうか? 自分独自の開発環境を構築しようとなった時には、設定ファイルが必要になってくると思います。(実際に触ったばかりなのでまだ確定できませんが。。。)

このことを踏まえてwebpack.config.jsファイルをプロジェクトフォルダ直下に作成します。

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: {
          loader: "babel-loader"
        }
      }
    ]
  }
};

ここで見て欲しいのが、エントリーポイントを記述していない点です。

その後、./src/index.jsをES6で記述します。

const data = [1, 2, 3];
const getArrData = () => console.log(...data);
console.log(getArrData)

npm run buildと実行してみください。 正しくES6 → ES5にトランスパイルされたかと思います。

最小限の構成ですとこのように設定ファイルなしで開発していくことができます。

次回はReact+webpack4での開発環境を紹介できればと思います。