スマートフォンサイトを大量に作る案件があったので、自分の作業用Gruntfileを作ったので晒します。最大のミソはgrunt-syncというものです。PCとスマホが同じWifiに接続されていれば、ブラウザの動作をsyncしてくれます。つまり、PCで作業し、PCのブラウザがLive Reloadすれば、スマホのブラウザも自動でリロードしてくれるので、表示確認の為にアップロードをする必要もなく、各端末を触ってリロードボタンを押すこともなく、iPhoneだろうがAndroidだろうが関係なくサクサク制作ができるわけです。AdobeのEdge Inspectみたいなことができるってことですね。Edge Inspectは使ってみましたが、スマホに専用アプリをインストールしなければならなかったりするので、会社の方針などで自由にインストール出来ないとかあれば、Gruntのほうが自由度高いと思います。自分の場合はよく接続が切れたりしてたのでやめました。

package.json

自分はjadeとstylusとcoffee-scriptが好きなので、主にこれらで制作する前提になってしまいます。他のパッケージは好みで追加や削除してください。

{
  "name": "",
  "version": "1.0.0",
  "licenses": [
    {
      "type": "All rights reserved",
      "url": ""
    }
  ],
  "author": "",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": "",
  "license": "BSD",
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-contrib-copy": "~0.4.1",
    "grunt-contrib-clean": "~0.5.0",
    "grunt-contrib-htmlmin": "~0.1.3",
    "grunt-contrib-csslint": "~0.1.2",
    "grunt-contrib-cssmin": "~0.6.2",
    "grunt-contrib-jst": "~0.5.1",
    "grunt-contrib-coffee": "~0.7.0",
    "grunt-contrib-qunit": "~0.3.0",
    "grunt-contrib-connect": "~0.5.0",
    "grunt-contrib-requirejs": "~0.4.1",
    "grunt-contrib-jshint": "~0.6.5",
    "grunt-contrib-jasmine": "~0.5.2",
    "grunt-contrib-uglify": "~0.2.7",
    "grunt-contrib-handlebars": "~0.5.12",
    "grunt-contrib-compress": "~0.5.3",
    "grunt-contrib-watch": "~0.5.3",
    "grunt-contrib-stylus": "~0.8.0",
    "grunt-contrib-jade": "~0.8.0",
    "grunt-contrib-imagemin": "~0.3.0",
    "grunt-contrib-less": "~0.7.0",
    "grunt-contrib-nodeunit": "~0.2.2",
    "grunt-contrib-yuidoc": "~0.5.0",
    "grunt-contrib": "~0.8.0",
    "grunt-coffeelint": "0.0.7",
    "grunt-simple-mocha": "~0.4.0",
    "grunt-autoprefixer": "~0.4.1",
    "grunt-styleguide": "^0.2.15",
    "grunt-browser-sync": "~0.5.6",
    "grunt-newer": "~0.6.1",
    "matchdep": "~0.3.0"
  }
}

ファイル構成

srcディレクトリが作業ディレクトリになります。srcの中に、jade, stylus, coffee, images, 必要であれば、vendorsを作ってください。

.
├── Gruntfile.coffee
├── src
│   ├── jade
│   ├── stylus
│   ├── coffee
│   ├── images
│   └── vendors
├── node_modules
└── package.json

Gruntfile.coffee

module.exports = (grunt) ->

  # load all grunt tasks
  (require 'matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks)

  grunt.loadTasks 'tasks'

  _ = grunt.util._
  path = require 'path'

  grunt.initConfig
    pkg: grunt.file.readJSON('package.json')
    # Metadata.
    banner: '/*! <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today(\'yyyy-mm-dd\') %>\n' + '<%= pkg.homepage ? \'* \' + pkg.homepage + \'\\n\' : \'\' %>' + '* Copyright (c) <%= grunt.template.today(\'yyyy\') %> <%= pkg.author.name %>;' + ' Licensed <%= _.pluck(pkg.licenses, \'type\').join(\', \') %> */\n'

    dir:
      src: 'src'
      jade: 'jade'
      styl: 'stylus'
      coffee: 'coffee'
      images: 'images'
      js: 'js'
      css: 'css'
      img: 'images'
      vendors: 'vendors'
      dist: 'dist'
      build: 'build'
      docs: 'docs'
      test: 'test'

    jade:
      dist:
        options:
          pretty: true, #htmlをインデント表記させる
        expand: true
        cwd: '<%= dir.src %>/<%= dir.jade %>'
        src: '**/*.jade'
        dest: '<%= dir.dist %>/'
        ext: '.html'

    stylus:
      dist:
        options:
          compress: false
        expand: true
        cwd: '<%= dir.src %>/<%= dir.styl %>/'
        src: '**/*.styl'
        dest: '<%= dir.dist %>/<%= dir.css %>/'
        ext: '.css'

    coffee:
      dist:
        expand: true
        cwd: '<%= dir.src %>/<%= dir.coffee %>'
        src: '**/*.coffee'
        dest: '<%= dir.dist %>/<%= dir.js %>'
        ext: '.js'

    htmlmin:
      build:
        options:
          removeComments: true
          collapseWhitespace: false
        expand: true
        cwd: '<%= dir.dist %>'
        src: '**/*.html'
        dest: '<%= dir.build %>'
        ext: '.html'

    cssmin:
      build:
        expand: true
        cwd: '<%= dir.dist %>/<%= dir.css %>'
        src: '**/*.css'
        dest: '<%= dir.build %>/<%= dir.css %>'
        ext: '.css'

    uglify:
      options:
        banner: '<%= banner %>'
        sourceMap: (path) ->
          path + '.map'
      build:
        expand : true
        src: '<%= dir.build %>/**/*.js'

    # 画像の圧縮
    imagemin:
      options:
        optimizationLevel: 7
        pngquant: false
      dist:
        expand: true
        cwd: '<%= dir.dist %>/<%= dir.images %>'
        src: '**/*.{jpg,jpeg,gif}'
        dest: '<%= dir.dist %>/<%= dir.img %>'

    # coffeeの文法チェック
    coffeelint:
      app: '**/<%= dir.coffee %>/*.coffee'

    # CSSのprefiexを補完
    autoprefixer:
      options:
        browsers: ['last 2 version', 'ie 8', 'ie 7', 'ie 6']
      dist:
        expand: true
        cwd: '<%= dir.dist %>/<%= dir.css %>'
        src: '**/*.css'
        dest: '<%= dir.dist %>/<%= dir.css %>/'
        ext: '.css'

    simplemocha:
      dist:
        src: '<%= dir.test %>/<%= dir.coffee %>/*.coffee'
      options:
        globals: ['should']
        timeout: 3000
        ignoreLeaks: false
        grep: '*-test'
        ui: 'bdd'
        reporter: 'tap'


    watch:
      options:
        nospawn: true
      jade:
        files: '<%= dir.src %>/**/*.jade',
        tasks: 'newer:jade:dist'
      stylus:
        files: '<%= dir.src %>/**/*.styl'
        tasks: [
          'newer:stylus:dist',
          'newer:autoprefixer:dist',
          'newer:styleguide:dist'
        ]
      coffee:
        files: '<%= dir.src %>/**/*.coffee'
        tasks: 'newer:coffee:dist'
      images:
        files: ['<%= dir.src %>/**/*.{gif,jpeg,jpg,png,svg,webp}']
        #tasks: ['clean:images', 'copy', 'imagemin']
        tasks: ['newer:imagemin:dist', 'copy', 'imagemin']
      vendors:
        files: ['<%= dir.src %>/<%= dir.vendors %>/**']
        tasks: ['copy:vendors']
      livereload:
        options:
          livereload: '<%= connect.options.livereload %>'
        files: [
          '<%= dir.dist %>/*.html',
          '<%= dir.dist %>/**/*.css',
          '<%= dir.dist %>/**/*.js',
          '<%= dir.dist %>/**/*.{gif,jpeg,jpg,png,svg,webp}'
        ]

    browser_sync:
      files:
        src: [
          '<%= dir.dist %>/*.html',
          '<%= dir.dist %>/**/*.css',
          '<%= dir.dist %>/**/*.js',
          '<%= dir.dist %>/**/*.{gif,jpeg,jpg,png,svg,webp}'
        ]
      options:
        server:
          baseDir: '<%= dir.dist %>'
        watchTask: true
        ghostMode:
          scroll: true
          links: true
          forms: true

    connect:
      options:
        port: 9000
        livereload: 35729
        hostname: 'localhost'
      livereload:
        options:
          open: true
          base: ['<%= dir.dist %>']

    copy:
      img:
        expand: true
        dot: true
        cwd: '<%= dir.src %>/<%= dir.images %>'
        dest: '<%= dir.dist %>/<%= dir.img %>'
        src: [
          '**/*.{gif,jpeg,jpg,png,svg,webp}',
        ]
      vendors:
        expand: true
        dot: true
        cwd: '<%= dir.src %>/<%= dir.vendors %>'
        dest: '<%= dir.dist %>/<%= dir.vendors %>'
        src: ['**']
      build:
        expand: true
        dot: false
        cwd: '<%= dir.dist %>/'
        dest: '<%= dir.build %>/'
        src: ['**']

    yuidoc:
      dist:
        name: '<%= pkg.name %>'
        description: '<%= pkg.description %>'
        version: '<%= pkg.version %>'
      options:
        paths: '<%= dir.src %>/<%= dir.coffee %>/'
        outdir: '<%= dir.docs %>/<%= dir.js %>'
        syntaxtype: 'coffee'
        extension: '.coffee'

    styleguide:
      dist:
        files:
          #'<%= dir.docs %>/<%= dir.css %>': '<%= dir.src %>/<%= dir.styl %>/**/*.styl'
          '<%= dir.docs %>/<%= dir.css %>': '<%= dir.dist %>/<%= dir.css %>/**/*.css'
          #'<%= dir.docs %>/<%= dir.css %>': '<%= dir.src %>/<%= dir.styl %>/**/*.sass'

    clean:
      dist:
        src: [
          '<%= dir.dist %>/**/*.html',
          '<%= dir.dist %>/<%= dir.js %>/**/*.js',
          '<%= dir.dist %>/<%= dir.css %>/**/*.css',
          '<%= dir.build %>',
          '<%= dir.docs %>'
        ]
      docs:
        src: '<%= dir.docs %>'
      images:
        src: ['<%= dir.dist %>/<%= dir.img %>']

    converttosjis:
      build:
        expand: true
        cwd: '<%= dir.dist %>/'
        src: [
          '<%= dir.dist %>/*.html',
          '<%= dir.dist %>/**/*.css',
          '<%= dir.dist %>/**/*.js',
        ]


  grunt.registerTask 'default', [
    'clean',
    'coffeelint',
    'simplemocha',
    'yuidoc'
    'jade:dist',
    'stylus:dist',
    'autoprefixer',
    'styleguide',
    'coffee:dist',
    'copy:img',
    'copy:vendors',
    'imagemin'
  ]
  grunt.registerTask 'sync', [
    'default',
    'browser_sync',
    'watch',
  ]
  grunt.registerTask 'build', [
    'default',
    'copy:build'
    'htmlmin:build',
    'cssmin:build',
    'uglify'
  ]

簡単な使い方

まずは、npm install して、package.json に書いてあるnode_modulesたちをインストールします。

$ npm install

インストールが完了したら、ダミーのjade, stylus, coffeeファイルを用意して、grunt syncコマンドを実行します。

$ grunt sync

すると、ブラウザが自動的に立ち上がって、URLがlocalhostではなく、PCがWi-Fiに接続されているIPアドレスになっていると思います。ここまで来たら、無事に成功です。

最後に、スマホでアクセスしてみよう!

同じWi-Fiに接続されているスマホでURLを入力してアクセスしてみると、同じ画面が表示されていると思います。作業ファイルはwatchで監視されているので、ファイルの変更があれば、自動でリロードすると思います。

もうお気づきかもしれませんが、このURLは、同じWi-Fiに繋がってる端末であれば、アクセスすることができます。例えば、組織のボスにプレゼンしたり、手直しを要求されたりした場合、ボスの端末にこのURLをアクセスしていただき、ライブコーディングで手直ししたり修正変更すると、端末を触ることなく、その場でどんどん出来上がる過程をみてもらうこともできます。自分はこれを使いながらページを手直ししていくと、「お前魔法使いみたいやなw」って言われました^_^;

ちょっと注意

例えば、index.jadeとiframe.jadeというファイルがあるとします。index.jadeの中に、iframe.jadeが、inline frameとしてコーディングされている場合、iframe先のファイルもgrunt-syncの影響を受けてしまいますので、iframe先のHTMLが呼び出された時に、ブラウザがiframe.htmlを呼び出してしまいます。iframeを使うときは、grunt-syncの挙動に要注意です。

【Grunt.js】ブラウザを同期してくれるgrunt-syncがスマホ制作で最強な件
Pocket

Tagged on:     

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です