読者です 読者をやめる 読者になる 読者になる

みかづきブログ その3

3ヶ月つづけてみました。

フロントエンドエンジニアがさくらVPS で Ubuntu + Nginx + Node.js + Express + webpackの環境を整えるまでの道のり - その6 Expressのディレクトリ調整とpm2の導入 😎

春ですね。^ ^

なにか新しいことをはじめたくなりますね。^ ^

前回はExpressの導入を行いました。
今回は、webpackを導入します。

kimizuka.hatenablog.com

kimizuka.hatenablog.com

kimizuka.hatenablog.com

kimizuka.hatenablog.com

kimizuka.hatenablog.com




ゴールまでの道のり

  1. VPSサーバ借りる
  2. Ubuntu入れる
  3. Nginx入れる
  4. nodebrew、Node.js入れる
  5. nmp入れる
  6. git入れる
  7. Express入れる
  8. webpack入れる
  9. ES2015をES5に変換できるようにする
  10. PostCSSをCSSに変換できるようにする ← 前回はここまで
  11. Expressのディレクトリ構成変える ← 今回はここから
  12. pm2入れる
  13. サイトつくる



今回のリポジトリ

github.com



前回、前々回はちょっと寄り道をして、webpackの環境を整えました。
今回は、前回、前々回の設定をExpressに取り込んでいきたいと思います。

kimizuka.hatenablog.com

kimizuka.hatenablog.com



適当なディレクトリをつくって移動

mkdir webpack-sample-express
cd webpack-sample-express

ソース用のディレクトリと書き出し用のディレクトリをつくる

mkdir _src
mkdir _src/js
mkdir _src/css
mkdir public
mkdir public/js
mkdir public/css

package.jsonをつくる

vim package.json
package.json
{
  "name": "webpack-sample-express",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "pm2 start ./bin/www -i max",
    "pm2stop": "pm2 stop all",
    "pm2list": "pm2 list",
    "build": "webpack",
    "watch": "webpack --watch & node ./bin/www"
  },
  "babel": {
    "presets": [
      "es2015",
      "es2017"
    ]
  },
  "dependencies": {
    "autoprefixer": "^6.7.7",
    "babel-core": "^6.24.1",
    "babel-loader": "^6.4.1",
    "babel-preset-es2015": "^6.24.1",
    "babel-preset-es2017": "^6.24.1",
    "body-parser": "~1.17.1",
    "cookie-parser": "~1.4.3",
    "css-loader": "^0.28.0",
    "debug": "~2.6.3",
    "express": "~4.15.2",
    "extract-text-webpack-plugin": "^2.1.0",
    "morgan": "~1.8.1",
    "pm2": "^2.4.4",
    "postcss-extend": "^1.0.5",
    "postcss-for": "^2.1.1",
    "postcss-loader": "^1.3.3",
    "postcss-nested": "^1.0.0",
    "postcss-simple-vars": "^3.1.0",
    "pug": "~2.0.0-beta11",
    "serve-favicon": "~2.4.2",
    "style-loader": "^0.16.1",
    "webpack": "^2.3.3"
  }
}

コンフィグファイルをつくる

vim webpack.config.babel.js
webpack.config.babel.js
import webpack from "webpack";
import ExtractTextPlugin from "extract-text-webpack-plugin";

module.exports = [{
  entry: {
    index : __dirname + "/_src/js/index.js"
  },
  output: {
    path: __dirname + "/public/js/",
    filename: "[name].bundle.js"
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: [
        /node_modules/
      ],
      use: [{
        loader: "babel-loader",
        options: {
          presets: [
            "es2015",
            "es2017"
          ]
        }
      }],
    }]
  },
  plugins: [
    new webpack.optimize.UglifyJsPlugin()
  ]
},{
  entry: {
    index: __dirname + "/_src/css/index.css"
  },
  output: {
    path: __dirname + "/public/css/",
    filename: "[name].bundle.css"
  },
  module: {
    rules: [{
      test: /\.css$/,
      use: ExtractTextPlugin.extract({
        fallback: "style-loader",
        use: "css-loader?minimize!postcss-loader"
      })
    }]
  },
  plugins: [
    new ExtractTextPlugin("[name].bundle.css")
  ]
}];

CSSのコンフィグファイルをつくる

vim postcss.config.js
postcss.config.js
module.exports = {
  plugins: [
    require("postcss-simple-vars")({
      silent: true
    }),
    require("postcss-nested"),
    require("postcss-for"),
    require("postcss-extend"),
    require("autoprefixer")({
      browsers: ["last 5 versions"]
    })
  ]
};

必要なモジュールをインストール

npm install

_src/js/index.jsを用意

vim _src/js/index.js
_src/js/index.js
import hello from "./hello.js";

hello.say();

_src/js/hello.jsを用意

vim _src/js/hello.js
_src/hello.js
export default class Hello {
  static say() {
    alert("HELLO.");
  }
}

_src/css/index.cssを用意

vim _src/css/index.css
_src/css/index.css
@charset "UTF-8";

$teal: #004D40;

%bg-teal {
  background: $teal;
}

body {
  @extend %bg-teal;

  display: flex;

  @for $i from 0 to 10 {
    [data-index=$i] {
      &:after {
        content: "$i";
      }
    }
  }
}

app.jsを用意

vim app.js
app.js
var express      = require("express");
var path         = require("path");
var favicon      = require("serve-favicon");
var logger       = require("morgan");
var cookieParser = require("cookie-parser");
var bodyParser   = require("body-parser");

var index = require("./routes/index");

var app = express();

// view engine setup
app.set("views", path.join(__dirname, "views"));
app.set("view engine", "pug");

// uncomment after placing your favicon in /public
// app.use(favicon(path.join(__dirname, "public", "favicon.ico")));
app.use(logger("dev"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));

app.use("/", index);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error("Not Found");
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get("env") === "development" ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render("error");
});

module.exports = app;

bin/www を作成

mkdir bin
vim bin/www
bin/www
#!/usr/bin/env node

/**
 * Module dependencies.
 */

var app   = require("../app");
var debug = require("debug")("app:server");
var http  = require("http");

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || "3000");
app.set("port", port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on("error", onError);
server.on("listening", onListening);

/**
 * Normalize a port into a number, string, or false.
 */

function normalizePort(val) {
  var port = parseInt(val, 10);

  if (isNaN(port)) {
    // named pipe
    return val;
  }

  if (port >= 0) {
    // port number
    return port;
  }

  return false;
}

/**
 * Event listener for HTTP server "error" event.
 */

function onError(error) {
  if (error.syscall !== "listen") {
    throw error;
  }

  var bind = typeof port === "string"
    ? "Pipe " + port
    : "Port " + port;

  // handle specific listen errors with friendly messages
  switch (error.code) {
    case "EACCES":
      console.error(bind + " requires elevated privileges");
      process.exit(1);
      break;
    case "EADDRINUSE":
      console.error(bind + " is already in use");
      process.exit(1);
      break;
    default:
      throw error;
  }
}

/**
 * Event listener for HTTP server "listening" event.
 */

function onListening() {
  var addr = server.address();
  var bind = typeof addr === "string"
    ? "pipe " + addr
    : "port " + addr.port;
  debug("Listening on " + bind);
}

routes/index.js を作成

mkdir routes
vim routes/index.js
routes/index.js
var express = require("express");
var router  = express.Router();

/* GET home page. */
router.get("/", function(req, res, next) {
  res.render("index", {
    title: "Express"
  });
});

module.exports = router;

view を作成

mkdir views
vim views/layout.pug
views/layout.pug
pdoctype html
html
  head
    title= title
    link(rel='stylesheet', href='/css/index.bundle.css')
  body
    block content
    script(src="/js/index.bundle.js")
vim views/index.pug
views/index.pug
extends layout

block content
  h1= title
  p Welcome to #{title}
vim views/error.pug
views/error.pug
extends layout

block content
  h1= message
  h2= error.status
  pre #{error.stack}

試しにビルド!

npm run build

最終的なファイル構成

webpack-sample-express/
 └ _src/
  └ js/
   └ hello.js
   └ index.js
  └ css/
   └ index.css
 └ app.js
 └ bin/
   └ www
 └ nodemodules/
   └ ...
   └ ...
 └ package.json
 └ postcss.config.js
 └ public/
   └ js/
    └ index.bundle.js
   └ css/
    └ index.bundle.css
 └ routes
   └ index.js
 └ views
   └ error.pug
   └ index.pug
   └ layout.pug
 └ webpack.config.babel.js

リポジトリ

github.com

リポジトリにプッシュ / リポジトリからプル

.sass-cache
node_modules

をignoreしてリポジトリにプッシュ。
リポジトリをcloneし、

npm start

IPアドレスの3000番にアクセスすると、

f:id:kimizuka:20170413211037p:plain

てってれー。
無事にExpressが起動しています。
しかもデーモン化しているのでずーっと動きます。

リバースプロキシの設定

しかし、せっかくなので3000番ではなく80番で動かしたいところ。
そこでリバースプロキシを設定します。

sudo vim /etc/nginx/conf.d/express.conf
express.conf
server {
        listen 80;
        server_name (さくらから割り当てられているドメイン);
        location / {
                proxy_pass http://127.0.0.1:3000;
        }
}
sudo nginx -s reload

で設定を反映。
これで、IPではなくドメインでアクセスしてみると、

f:id:kimizuka:20170413211037p:plain

てってれー。
無事にExpressが起動しています。
(IP直打ちだとNginxのデフォルト画面になりますが)



以上で長かった初期設定が終わりました。
あとは思う存分サイトをつくるだけです。