JavaScriptのimportとrequireの違いって?
JavaScriptで開発をしている時に、自分で作成したファイルやnodeモジュールなどを読み込む時にimport
やrequire
を使う時があると思います。
そういえばこの二つの違いってなんだろうと疑問に思ったのでその違いを探っていきたいと思います。
結論を先に述べると、require
がnodeの書き方でimport
がES2015の記述方法です。
因みに前者がCommonJSと呼ばれるモジュールシステム、後者がES Modulesです。
import
は全ブラウザでサポートしているわけではないので、babelなどで変換する必要があります。
require
は当たり前のことですが、nodeがない環境では使用することができません。
ここで疑問が生まれます。
フロントエンドで開発をしていくとなるとnodeを使った開発が主流になると思います。node
側でどのようにES Modulesを解釈しているのでしょうか?
この両者を区別するアルゴリズムが存在します。
CommonJS
とES Modules
によって処理内容を切り替えているようです。
こちらが参考にさせていただいた記事になります。
yosuke-furukawa.hatenablog.com
ではES Modules
の記述方法を見ていきましょう。
ES Modules
default exports
default exportsはexport default (渡したい変数や関数)
の形式で記述します。以下のコードを見てください。
export default function(name) { console.log(`My name is, ${name}!`); }
default imports
import getName from './greet.js'; getName('Tom');
このとき、greet.jsから渡された関数は、import先の変数getNameに代入されています。 export文では文字列や数値などの値、class、オブジェクトや配列などのリテラルも指定して公開できます。
named exports
こちらは上記のdefault exports
と違って1つのモジュールから個別にexportしたいものに変数名をつける必要があります。
export const name = "tanaka"; export const fruits = ["Apple", "Orange", "Banana"]; exports const num = 40;
それぞれ変数名をつけてexportします。
named imports
上で定義したモジュールを読み込む際にはimport先でimport { (変数名) } from (パス名)
の形式で、分割代入を記述するときのよう変数名を単一あるいは複数列挙します。
import { name, fruits } from './sub.js';
もしimport先から公開されている値のすべてを読み込みたいのであれば、任意の名前空間内に配置できます。
import * as module from './sub.js'; console.log(module.name); // "tanaka"
また変数名を読み込み側で変更することもできます。
import { name as myName } from './sub.js';
sub.js
で定義されている変数name
をMyname
と変更しています。
import元と同一ディレクトリのモジュールを読み込む場合には、./
と記述しなくてはいけません。
それ以外の読み込みについては、HTMLからほかのリソースを指定する場合のパス指定のルールと一緒です。/
から書き始めることで、ルートパスでの指定もできます。
// 同一階層のmenu.js を取得 import menu from './menu.js'; // 上の階層のscroll.js を取得 import scroll from '../scroll.js'; // ルートパスのroot.js を取得 import root from '/root.js';
また拡張子についても気をつける点があります。 webpackやBrowserifyを使っていると、.jsの拡張子を省いていてもモジュールを取得してくれることに慣れてしまっているかもしれませんね。
次回は、CommonJSについての書き方やルールについて解説していきたいと思います。
Reactとaxiosを使ってgithubのAPIからデータを取得してみる
今回はReactとaxiosを使ってgithubのAPIからデータを取得しようと思います。
まず、初めにプロジェクトフォルダを作ってください。
作成後、プロジェクトフォルダに移動して以下のコマンドを実行してください。
create-react-app プロジェクト名
create-react-appはreactの環境を簡単に作成することができる超便利ツールです。
その後、yarn start
自動でブラウザが立ち上がります。
編集するファイルはApp.jsとApp.cssファイルだけになります。 今回はgithub APIのデータをaxiosを使って取得することに集中したいのでコンポーネント化などはしません。
まず、必要なパッケージをインストールします。
yarn install -D axios
App.jsの全体のコードになります。 順を追って説明していきたいと思います。
import React, { Component, Fragment } from 'react'; import axios from 'axios'; import User from './App.css' class App extends Component { constructor(){ super(); this.state = { userDatas:[] }; } componentWillMount(){ const request = axios.create({ baseURL: 'https://api.github.com' }) request.get('/users/ユーザー名') .then(res => { this.setState({ userDatas: res.data }); }) } render() { return ( <Fragment> <header className="header"></header> <div className="user"> <p className="user_img"><img src={this.state.userDatas.avatar_url}/ ></p> <div className="user_name">{this.state.userDatas.name}</div> <div className="user_id">{this.state.userDatas.login}</div> <div className="user_followArea"> <div className="user_followers">followers:{this.state.userDatas.followers}</div> <div className="user_following">following:{this.state.userDatas.following}</div> </div> </div> </Fragment> ); } } export default App;
まずは1行目から見てみましょう。
import React, { Component, Fragment } from 'react'; import axios from 'axios';
FragmentとはReact v16から追加された機能になります。 簡単に言うとrender関数の中で余計なDOMノードを追加することが不要になります。 そのことの記事を書いたのでよかったら参考にしてください。
constructor(){ super(); this.state = { userDatas:[] }; }
constructorの中身についてですが、まずはstateにuserDatasを登録します。
次のコードが今回のコードのキーポイントになります。 componentWillMountというのはReactのコンポーネントのライフサイクルになります。 文字通り、コンポーネントがマウントされる前になんらかの処理を施すことができます。
componentWillMount(){ const request = axios.create({ baseURL: 'https://api.github.com' }) request.get('/users/ユーザー名') .then(res => { this.setState({ userDatas: res.data }); }) }
baseURLでgithubのAPIにアクセスします。 request.getでgithubの自分のデータをjson形式で取得しています。 その後、データを取得した後にsetStateでuserDatesにデータを入れています。
render() { return ( <Fragment> <header className="header"></header> <div className="user"> <p className="user_img"><img src={this.state.userDatas.avatar_url}/ ></p> <div className="user_name">{this.state.userDatas.name}</div> <div className="user_id">{this.state.userDatas.login}</div> <div className="user_followArea"> <div className="user_followers">followers:{this.state.userDatas.followers}</div> <div className="user_following">following:{this.state.userDatas.following}</div> </div> </div> </Fragment> ); }
ここではstateのデータを整形し表示しているだけになります。
ブラウザで見るとこのよう表示になります。(Cssは別途設定しています。)
とっても手軽で簡単ですね。是非試してみてください!今回は初めからjson形式データを取得できていましたが、サーバーから取得するデータの形式がjsonではないときなどあります。どのような形式でデータが渡ってきているかなど意識することは大切です。
簡単ではありますが、以上になります。
Web Componentsを試してみた
今回はWeb Componentsを使って実際にコードを書いていきたいと思います。
アイコンと文言がセットになったざーーっくりとしたプロフィール用のテンプレートを例に作っていきます。
いきなりですが、↓が全体のコードになります。 一つ一つ解説を交えながら進めていきます!
<!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>Document</title> <style> </style> </head> <body> <profile-template></profile-template> <profile-template> <img src='images/jyojyo.jpg' slot="img" alt=''> <p slot="description">よちよち開発よちよち開発よちよち開発よちよち開発</p> </profile-template> <script> class Profile extends HTMLElement { static get template(){ return ` <style> .profile { display: flex; align-items:center; justify-content: space-around; } .profile_img { width:200px; } img, #img::slotted(*) { width:200px; } </style> <div class="profile"> <p class="profile_img"> <slot name="img" id="img"> <img src="images/riki.jpg"> </slot> </p> <slot name="description">滑舌の悪いおじさん滑舌の悪いおじさん滑舌の悪いおじさん</slot> </div> `; } constructor(){ super(); this.attachShadow({ mode: 'open' }).innerHTML = Profile.template; } } customElements.define('profile-template', Profile); </script> </body> </html>
-------以下から解説-------
class Profile extends HTMLElement { //省略 }
ここではextends HTMLElement
でHTMLElement を継承します。
constructor(){ super(); this.attachShadow({ mode: 'open' }).innerHTML = Profile.template; }
attachShadow を利用することでShadow DOMを有効にしています。その後innerHTML
でstyleとHTMLを突っ込んでいます。
<div class="profile"> <p class="profile_img"> <slot name="img" id="img"> <img src="images/riki.jpg"> </slot> </p> <slot name="description"> 滑舌の悪いおじさん滑舌の悪いおじさん滑舌の悪いおじさん </slot> </div>
htmlのコードの中にslotという文字があります。
Shadow DOM は、
customElements.define('profile-template', Profile);
customElements.define
でCustom Elementを定義しています。
第一引数が実際に使用する要素のタグ名で、第二引数はクラス名になります。ブラウザにCustom Elementだと認識させるためにタグ名はダッシュをつけます。
ブラウザに表示させた結果はこちらになります。(スタイルがイケてなくてすみません。。。)
まだ一部のブラウザ標準でまだ使用することはできないので、未対応のブラウザにも Web Componentsを使用できるためのPolyllを導入することが必要になると思います。
Web Componentsとは
今回はWeb Componentsについて自分の理解も深めるために書いていきます。
Web Componentsについては公式サイトにおいて下記のように説明されています。
Web components are a set of web platform APIs that allow you to create new custom, reusable, encapsulated HTML tags to use in web pages and web apps. Custom components and widgets build on the Web Component standards, will work across modern browsers, and can be used with any JavaScript library or framework that works with HTML.
簡単にいうとWeアプリケーションなどで共通となる部品を独自のタグを使っていつでも呼び出せる(使える)ようにしようといった意味になります。
header
タグやfooter
などは何を意味しているのか視覚的にわかりますが、div
タグとか見ても作った本人ならまだしも、他の人がそのコードを見た時にどのような意味なのか実際に表示されたものと照らし合わせて見ないとわかりずらいですよね?
ReactやVueなどは共通部品となるものなどをコンポーネント化してそれぞれ役割に合った命名をするかと思います。また大切なのはそれぞれが独立しても機能するために、HTML/CSS/JavaScriptなどを一つのスコープとしてコンポーネント化します。そうすることで例えばCSSのグローバルスコープの汚染問題を回避することができます。
また更に重要なこととしてWeb Componentsはブラウザの標準の機能を使用するので特別なビルド環境などが不要になります。
ではここでWeb Componentsを構成する4つの要素について説明していきたいと思います。
1 Custom Elements
Custom ElementsとはHTMLのタグに独自の名前をつけることができるものです。すでにこのことについては言及しましたが、div
タグなどがたくさんある時よりもheader
やfooter
など役割をもたせ、視覚的にわかりやすい方がコーディングがしやすいです。
文書構造に意味付けとして非常に大切な要素だと思います。
2 Shadow DOM
CSS スコープ、DOM カプセル化、コンポジションなどを活用し、Custom Elementsで新しいHTMLを作成します。したがってShadow DOMだけでェブ コンポーネントを作成するわけではありません。 詳細を知りたい方はこちらを参考にしてみてください。
3 HTML Imports
CSSやJavaScriptなどを含むHTMLファイルを一つのモジュールとしてロードすることができる仕組みです。
4 HTML Template
普段使用しているタグなどを<template>
要素で囲い、テンプレートを宣言します。宣言するだけでは実際に描画されません。JavaScriptなどを使用することでテンプレートを描画します。
Web Componentsは上の4つの仕様から構成されています。 実際に手を動かしてみないと実感が湧かないと思いますので次回はコードを例にしながらWeb Componentsの理解を深めていこうと思います。
jQueryを使わずES2015でスライダー対応のポップアップテンプレートをつくってみた。
今回はスライダー対応のポップアップテンプレートを作成してみました。簡単なポップアップのテンプレートが欲しい場合はこちらを参考にしてみてください!
スライダー対応のポップアップのイメージはこちら になります。
ライブラリに依存するることは学習コストが掛かるので極力使いたくはありません。ですがプロジェクトによってはスケジュールやメンバーなどを考慮して使用することが正しいときもあるでしょう。
ですが、今回はjQueryなどを使わずに流用できるものを紹介します。
早速ですがコードを見てみましょう。
<!DOCTYPE html> <html lang='en'> <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>Document</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> <h1>ポップアップデモ</h1> <p>画像をクリック</p> <p><img src='images/img_01.jpg' alt='' class="popup_image"></p> <p>大海原だぁぁ</p> <p><img src='images/img_02.jpg' class="popup_image" alt=''></p> <p>海もいいけど山菜食べたい</p> <p>山登ろう</p> <p>頂上の風景綺麗だな</p> <p><img src='images/img_03.jpg' alt='' class="popup_image"></p> <p>気づけばもう冬かぁ</p> <p><img src='images/img_04.jpg' alt='' class="popup_image"></p> <!---ポップアップ--> <div class="popupSlider" id="popupWrap"> <div class="popupSlider_content"> <div class='closeBtn' id="js-closeBtn">X</div> <p class="poupSldier_content_arrow prev" id="sliderPrevArrow"></p> <p class="popupSlider_content_img"><img src='' alt='' class="" id="poupSliderImg"></p> <p class="poupSldier_content_arrow next" id="sliderNextArrow"></p> </div> </div> <!-- <script src="js/Popup.js"></script> --> <script src="js/PopupSlider.js"></script> </body> </html>
img { max-width: 100%; } .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; } .popup_image { width: 400px; cursor: pointer; } /* ポップアップのスライダー用のクラス*/ .popupSlider { width: 100vw; height: 100vh; position: fixed; opacity: 0; top: 0; left: 0; background:rgba(0, 0, 0, .6); display: flex; align-items: center; justify-content: center; z-index: -1; transition: all .3s; } .popupSlider.is-active { opacity: 1; z-index: 1000; } .popupSlider_content { display: flex; width: 600px; justify-content: center; align-items: center; position: relative; padding: 30px; background: #fff; } .popupSlider_content_img { width:100%; padding: 0 20px; } .poupSldier_content_arrow:before { content: "◀"; position: absolute; display: block; color: #fff; display: flex; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } .poupSldier_content_arrow { width: 80px; height: 60px; background: #000; cursor: pointer; margin: 0; border-radius: 50%; padding: 0; position: relative; } .poupSldier_content_arrow.next { transform: rotate(180deg); } .closeBtn { position: absolute; top: 10px; right: 40px; position: absolute; top: 10px; right: 15px; border-radius: 50%; border: 1px solid #323232; padding: 10px; width: 20px; height: 20px; background: #323232; color: #fff; display: flex; align-items: center; justify-content: center; }
class PopupSlider { constructor(imageElements) { this.el = document.getElementById("popupWrap"); this.imgEl = document.getElementById("poupSliderImg"); this.closeBtn = document.getElementById("js-closeBtn"); this.allImgElms = imageElements; this.setEventListeners(); } togglePopupState(flag) { if (flag) { this.el.classList.add("is-active") } else { this.el.classList.remove("is-active") } } changeImage(src) { this.imgEl.setAttribute("src", src); } slideNext(src) { this.changeImage(src); } slideBack(src) { this.changeImage(src); } setEventListeners() { for(let i = 0; i < this.allImgElms.length; i++) { this.allImgElms[i].addEventListener("click", e => { const clickImgSrc = e.target.getAttribute("src"); this.imgEl.setAttribute("src", clickImgSrc) this.togglePopupState(true); }); } this.closeBtn.addEventListener("click", e => { this.togglePopupState(false); }) document.getElementById("sliderNextArrow").addEventListener("click", e => { const currentSrc = document.getElementById("poupSliderImg").getAttribute("src"); for(let i = 0; i < this.allImgElms.length; i++) { const src = this.allImgElms[i].getAttribute("src"); if (src === currentSrc) { if (this.allImgElms.length <= i+1) { this.slideNext(this.allImgElms[0].getAttribute("src")); return }; this.slideNext(this.allImgElms[i+1].getAttribute("src")); } } }); document.getElementById("sliderPrevArrow").addEventListener("click", e => { const currentSrc = document.getElementById("poupSliderImg").getAttribute("src"); for(let i = 0; i < this.allImgElms.length; i++) { const src = this.allImgElms[i].getAttribute("src"); if (src === currentSrc) { if (Array.from(this.allImgElms).indexOf(this.allImgElms[i]) <= 0) { this.slideBack(this.allImgElms[this.allImgElms.length -1].getAttribute("src")); return; }; this.slideBack(this.allImgElms[i-1].getAttribute("src")); } } }); } } const imageElements = document.getElementsByClassName("popup_image"); const slider = new PopupSlider(imageElements); const toArray = (htmlCollection) => { Array.prototype.slice.call(htmlCollection); }
ここでテンプレートとして使用するために気をつける箇所いくつかあります。
- ポップアップ&スライドショーで表示させたいimgタグに
popup_image
クラスを付与することです。
const imageElements = document.getElementsByClassName("popup_image");
上記のコードのクラス名をご自身の好きなクラス名にしていただいても構いません!
またArray.from
とコードの中で出てきていますが、こちらは配列型のオブジェクトから新しい配列インスタンスを生成しています。
ここでは配列にしたデータの方が扱い易くなるからです。
ポップアップによってスタイルを変更したい場合は、cssなどで調整してみてください。
簡単ではありますが以上になります。
Node+Mysqlでブラウザにデータを表示させてみる
NodeとMysqlを使ってブラウザにデータを表示させてみようと思います。
大まかな流れとしましては
- mysqlに接続
- データを取得
- viewファイルにデータを渡す
- viewファイルでデータの整形をして表示させる
ディレクトリ構成はこのようになります。
root ├ index.js ├ views | ├ css | style.css | └ index.pug └ package.json
まずはじめにプロジェクトフォルダを作成し、移動します。
そこでnpm init -y
と実行し、package.jsonファイルが作成されます。
その後、必要なパッケージをインストールします。
npm i -D mysql pug express
{ "name": "express_sample", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "express": "^4.16.3", "mysql": "^2.15.0", "pug": "^2.0.1" } }
index.jsファイルにmysqlのからテーブルのデータの取得、ルーティングの設定をしたいと思います。
const express = require('express'); const app = express(); const mysql = require('mysql'); const connection = mysql.createConnection({ host : 'localhost', user : 'hoge', password : 'password', database : 'sample_db' }); app.set('view engine', 'pug'); app.use(express.static('views')); const recordLog = function (req, res, next) { console.log('localhost:3000にアクセスしました'); next(); }; app.use(recordLog); app.get('/', function (req, res) { let sql = 'select * from sample_db.personal'; connection.query(sql, (err, rows, fields) => { if (err) throw err; res.render('index', { title: 'node + mysql practice', PesoralDatas: rows}); }); }); app.listen(3000);
あらかじめmysqlにデータベースとテーブルを作成しておきました。
データベース名はsample_dbでテーブル名がpersonalとなります。
ファイルの中身を解説していきます。
const connection = mysql.createConnection({ host : 'localhost', user : 'hoge', password : 'password', database : 'sample_db' });
host・・・データベースのホスト名
user・・・データベースにログインしているユーザー名
password・・・パスワード
database・・・データベース名
app.set('view engine', 'pug'); app.use(express.static('views'));
こちらhtmlのテンプレートエンジンとしてpugを使用することを宣言しています。
静的アセットディレクトリーをviews
と指定しています。
app.get('/', function (req, res) { let sql = 'select * from sample_db.personal'; connection.query(sql, (err, rows, fields) => { if (err) throw err; res.render('index', { title: 'node + mysql practice', PesoralDatas: rows}); }); });
localhost:3000
でアクセスした時にsample_dbにあるpersonalテーブルに接続します。
その後、index.pugファイルにこちら側で指定したタイトルの値とカラムのデータを渡しています。
viewsディレクトリ直下にindex.pugファイルを作成します。
html head title #{title} link(rel="stylesheet" href="css/style.css") body h1 Person Datas each person in PesoralDatas .person p.person__id id #{person.id} p.person__old old #{person.old} p.person__name name #{person.name}
pugではeach文が使用できるので、受け取ったデータを整形して表示させます。
cssファイルはこちらになります。
.person { border: 1px solid #323232; padding: 10px; } .person + .person { margin-top: 30px; }
これで準備が整いました。
プロジェクトフォルダ直下でnode index.js
と実行してください。
その後、localhost:3000
にアクセスしてみてください。
このように表示できれば成功です!! フロントからデータベースまで一通り触ることができました。
全体を通じてexpressは本当に手軽に利用できるものだと思いました。ルーティングからローカルサーバーの起動、テンプレートエンジンの設定(nodeで動いているのでejsも利用可能)など視覚的でわかりやすいです。
mysqlは全く触ったことがなかったのですが、ユーザーを作成し、実際にテーブルにカラムデータを入れるところまで行いました。
使用したコマンドを備忘録として残しておいたのでよかったら参考にしてみてください。
簡単ではありますが以上になります。
mysqlコマンドの備忘録
今後業務でmysqlを使用していくことが多くなってくると思うので、備忘録としてよく使うコマンドを書いていこうと思います。
ログイン中のユーザーを確認する
select USER();
テーブルの中のカラムを確認する
desc テーブル名;
ユーザーを追加する
create user 'ユーザー名'@localhost identified by "パスワード";
作成したユーザーでMySQLサーバへ接続する
mysql -u "ユーザー名" -p
データベースの作成
create database データベース名;
データベースの一覧確認
show databases;
データベースの選択
use データベース名;
ユーザーに権限追加
grant {権限の内容} on {権限の対象} to {ユーザー名}@{ホスト名} identified by {パスワード}
データベースにあるテーブルを参照する時
show tables from データベース名;
テーブルの削除
drop table テーブル名
テーブルの中身を確認
select * from テーブル名
データベースの削除
drop database `データベース名`
mysqlで接続しているデータベースサーバのホスト名を確認する方法
show variables like 'hostname';
まだ学び始めたばかりなので今後更に追加していきたいと思います! 簡単ではありますが以上になります。