Reactでイメージとウェブフォントを使う方法

2019-06-18

Webpack(폰팩)을 기반으로 만든 React(리액트) 프로젝트에서 이미지(image)와 웹 폰트(font)를 사용하는 방법에 대해서 알아봅니다.

概要

会社でReact(リアクト)を使って新しプロジェクトを作ることになりました。それでWebpack(ウェブパック)を使ってReact(リアクト)プロジェクトを設定しています。今回のブログポストではWebpack(ウェブパック)をベースに作ったReact(リアクト)プロジェクトでリソース(Resource)であるイメージ(image)とウェブフォント(Font)を使う方法について説明します。

このブログで紹介してるソースコードはギットバう(Github)で確認できます。

プロジェクト準備

ここで使うReact(リアクト)プロジェクトは下記のような内容が適用されたプロジェクトです。詳しく内容は各ブログポストを確認してください。

以前のブログポストでプロジェクトを生成したら下記のようなフォルダ構造が出来上がります。私たちはreact_router라는の名前ではなくreact_image_fontの名前でプロジェクトを生成しました。

|-- src
|   |-- Components
|   |   |-- Title
|   |   |   |-- index.tsx
|   |-- Features
|   |   |-- Page1
|   |   |   |-- index.tsx
|   |   |-- Page2
|   |   |   |-- index.tsx
|   |   |-- Top
|   |   |   |-- index.tsx
|   |-- index.html
|   |-- App.tsx
|-- .babelrc
|-- package.json
|-- webpack.config.js

モジュールインストール

Webpack(ウェブパック)をベースに作ったReact(リアクト)プロジェクトでイメージウェブフォントを使うためWebpack(ウェブパック)のfile-loaderurl-loaderが必要です。下記のコマンドでfile-loaderurl-loaderをインストールします。

npm install --save-dev file-loader, url-loader
  • file-loader: Webpack(ウェブパック)で実際使ってるファイルをコピーする時使います。
  • url-loader: Webpack(ウェブパック)でファイルサイズが小さなファイルをバンドルファイル(Bundle)で作る時使います。

Webpack修正

インストールしたモジュール(file-loader, url-loader)を使うためwebpack.config.jsを開いて下記のように修正します。

...
module.exports = {
  mode: process.env.NODE_ENV,
  entry: {
    ...
  },
  output: {
    ...
  },
  module: {
    rules: [
      ...
      {
        // write image files under 10k to inline or copy image files over 10k
        test: /\.(jpg|jpeg|gif|png|svg|ico)?$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              fallback: 'file-loader',
              name: 'images/[name].[ext]',
            },
          },
        ],
      },
      {
        // write files under 10k to inline or copy files over 10k
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 10000,
              fallback: 'file-loader',
              name: 'fonts/[name].[ext]',
            },
          },
        ],
      },
    ],
  },
  resolve: {
    ...
  },
  plugins: [
    ...
  ],
  devServer: {
    ...
  },
};

2つの設定が似てるので1つの設定だけ詳しくみてみます。

{
  // write image files under 10k to inline or copy image files over 10k
  test: /\.(jpg|jpeg|gif|png|svg|ico)?$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 10000,
        fallback: 'file-loader',
        name: 'images/[name].[ext]',
      },
    },
  ],
},
  • test: /\.(jpg|jpeg|gif|png|svg|ico)?$/,: 当該ファイルを扱いします。
  • loader: 'url-loader',: url-loaderを使います。
  • limit: 10000,: ファイルサイズが10kより小さい場合テキストで使った部分に直接入れます。(バンドルを作る)
  • fallback: 'file-loader',: ファイルサイズが10kより大きい場合、file-loaderを使ってファイルをコピーします。
  • name: 'images/[name].[ext]',: コピーする時ファイルをイメージ(image)フォルダにファイル名(name)と拡張子(ext)の形でコピーします。

ウェブフォント適用

明確にウェブフォント(Font)が適用されたか確認するためGoogle FontのAguafina Scriptを使ってテストします。まず、下記のリンクでGoogle Fontに移動してウェブフォント(Font)をダウンロードします。

ウェブフォント(Font)をダウンロードしたらsrc/Assets/Fontsフォルダを作って当該ファイルをコピーします。そしてsrc/App.tsxを開いて下記のように修正します。

import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { createGlobalStyle } from 'styled-components';

import Router from './Router';

const GlobalStyles = createGlobalStyle`
  @font-face {
    font-family:'AguafinaScript';
    src: url(${require('~/Assets/Fonts/AguafinaScript-Regular.ttf')});
  }
  body {
    font-family: 'AguafinaScript', sans-serif;
  }
`;

interface Props {}
const App = ({  }: Props) => {
  return (
    <>
      <GlobalStyles />
      <Router />
    </>
  );
};

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

私たちが作ったReact(リアクト)プロジェクトはstyled-componentsが適用されています。styled-componentsのcreateGlobalStyleを使ってグローバルスタイル(Global Style)を下記のように作りました。

const GlobalStyles = createGlobalStyle`
  @font-face {
    font-family:'AguafinaScript';
    src: url(${require('~/Assets/Fonts/AguafinaScript-Regular.ttf')});
  }
  body {
    font-family: 'AguafinaScript', sans-serif;
  }
`;
  • src: url(${require('~/Assets/Fonts/AguafinaScript-Regular.ttf')});: 私たちはurl-loaderとfile-loaderを使っていますのでrequireを使って当該ファイルを読んできます。

このようにグローバルスタイル(Global Style)を下記のように適用しました。

const App = ({  }: Props) => {
  return (
    <>
      <GlobalStyles />
      <Router />
    </>
  );
};

イメージを使う方法

イメージを使うためsrc/Assets/imagesフォルダを作ってイメージファイルをコピーします。ここには10kより大きなpngファイルと10kより小さいファイルを比較するため追加しました。そしてイメージを使う部分(src/Features/Top/index.tsx)を開いて下記のように修正します。

...
const Top = ({ match, history, location }: Props) => {
  ...
  return (
    <div>
      ...
      <img src={require('~/Assets/Images/logo.png')} />
      <img src={require('~/Assets/Images/ic_account.png')} />
      <img src={require('~/Assets/Images/ic_account.svg')} />
    </div>
  );
};

export default Top;

ウェブフォント(Font)を使う時と同じように、requireを使ってファイルを読んできました。

確認

今まで作った内容を確認するため下記のコマンドでWebpack(ウェブパック)開発サーバーを実行します。

npm start

そしたら下記のようにウェブフォント(Font)が適用された画面とイメージ(image)がローディングされた画面が見えます。

WebpackをベースにしたReactプロジェクトでウェブフォントとイメージを使う方法

右のソースコードを見れば分かると思いますが、10kより小さいファイルは1つのファイルでバンドリング(Bundle)されたことが確認できます。

下記のコマンドでビルド(Build)してみましょう。

npm run build

そしたら下記のようにdistフォルダに10kより大きいイメージファイルとウェブフォント(Font)ファイルがコピーされたことが確認できます。

WebpackをベースにしたReactプロジェクトでウェブフォント、イメージをコピー

Buy me a coffeeBuy me a coffee
Posts