Posted at

Vue.js 2.0 の Single File Components を試してみる

More than 1 year has passed since last update.

http://vuejs.org/guide/single-file-components.html

https://github.com/vuejs-templates/webpack-simple

今回はVue.js 2.0のコンポーネントを1つのファイルに纏めて定義する機能を見ていきます。

npmやらWebpackやらBrowserifyが必要なようなので、cloud9上でやります。

なおVue.jsはテンプレート(HTML)、ロジック(javascript)、スタイル(CSS)は本来1つであり、1つのファイルにまとめたほうが開発効率が上がるという思想のため、すべて.vueファイル上に記述するようです。

https://jp.vuejs.org/2015/10/28/why-no-template-url/


Getting Started

はい。やることはコマンドラインツール(CLI)をインストールしてサンプルプロジェクト立ち上げるだけです。

CLIのインストール:npm install -g vue-cli

~/workspace/vue $ npm install -g vue-cli

npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue
/home/ubuntu/.nvm/versions/node/v4.2.4/bin/vue -> /home/ubuntu/.nvm/versions/node/v4.2.4/lib/node_modules/vue-cli/bin/vue
vue-cli@2.4.0 /home/ubuntu/.nvm/versions/node/v4.2.4/lib/node_modules/vue-cli
├── semver@5.3.0
├── uid@0.0.2
├── commander@2.9.0 (graceful-readlink@1.0.1)
├── validate-npm-package-name@2.2.2 (builtins@0.0.7)
├── chalk@1.1.3 (supports-color@2.0.0, escape-string-regexp@1.0.5, ansi-styles@2.2.1, has-ansi@2.0.0, strip-ansi@3.0.1)
├── minimatch@3.0.3 (brace-expansion@1.1.6)
├── ora@0.2.3 (object-assign@4.1.0, cli-spinners@0.1.2, cli-cursor@1.0.2)
├── rimraf@2.5.4 (glob@7.1.1)
├── consolidate@0.14.1 (bluebird@3.4.6)
├── read-metadata@1.0.0 (yaml-js@0.0.8)
├── request@2.75.0 (aws-sign2@0.6.0, forever-agent@0.6.1, is-typedarray@1.0.0, caseless@0.11.0, tunnel-agent@0.4.3, oauth-sign@0.8.2, stringstream@0.0.5, isstream@0.1.2, json-stringify-safe@5.0.1, aws4@1.4.1, extend@3.0.0, tough-cookie@2.3.1, node-uuid@1.4.7, qs@6.2.1, combined-stream@1.0.5, mime-types@2.1.12, form-data@2.0.0, hawk@3.1.3, bl@1.1.2, http-signature@1.1.1, har-validator@2.0.6)
├── metalsmith@2.2.0 (is-utf8@0.2.1, absolute@0.0.1, has-generators@1.0.1, win-fork@1.1.1, thunkify@2.1.2, clone@0.1.19, stat-mode@0.2.2, async@0.9.2, is@2.2.1, unyield@0.0.1, chalk@0.5.1, ware@1.3.0, recursive-readdir@1.3.0, fs-extra@0.10.0, co-fs-extra@0.0.2, gray-matter@2.0.2)
├── download-git-repo@0.2.1 (git-clone@0.1.0, download@4.4.3)
├── handlebars@4.0.5 (async@1.5.2, source-map@0.4.4, optimist@0.6.1, uglify-js@2.7.3)
├── inquirer@0.12.0 (ansi-regex@2.0.0, strip-ansi@3.0.1, ansi-escapes@1.4.0, rx-lite@3.1.2, through@2.3.8, cli-width@2.1.0, figures@1.7.0, cli-cursor@1.0.2, run-async@0.1.0, readline2@1.0.1, string-width@1.0.2, lodash@4.16.4)
└── async@2.0.1 (lodash@4.16.4)
~/workspace/vue $

1つワーニングでましたけど、まあいいでしょう。

つづいてサンプルプロジェクトを作成: vue init webpack-simple my-project

~/workspace/vue $ vue init webpack-simple my-project

This will install Vue 2.x version of template.

For Vue 1.x use: vue init webpack-simple#1.0 my-project

? Project name my-project
? Project description A Vue.js project
? Author ****** <********@gmail.com>

vue-cli · Generated "my-project".

~/workspace/vue $

設定を聞かれるので全部エンターで初期値のままいきます。

つぎにプロジェクトに移動: cd my-project

初期化:npm install

~/workspace/vue $ cd my-project

~/workspace/vue/my-project $ npm install
npm WARN optional dep failed, continuing fsevents@1.0.14
file-loader@0.9.0 node_modules/file-loader
└── loader-utils@0.2.16 (object-assign@4.1.0, big.js@3.1.3, emojis-list@2.1.0, json5@0.5.0)

babel-loader@6.2.5 node_modules/babel-loader
├── object-assign@4.1.0
├── loader-utils@0.2.16 (big.js@3.1.3, emojis-list@2.1.0, json5@0.5.0)
└── mkdirp@0.5.1 (minimist@0.0.8)

cross-env@3.1.2 node_modules/cross-env
└── cross-spawn@3.0.1 (lru-cache@4.0.1, which@1.2.11)

vue@2.0.1 node_modules/vue

vue-loader@9.5.1 node_modules/vue-loader
├── object-assign@4.1.0
├── vue-hot-reload-api@2.0.6
├── vue-template-es2015-compiler@1.0.0
├── vue-style-loader@1.0.0
├── hash-sum@1.0.2
├── loader-utils@0.2.16 (big.js@3.1.3, emojis-list@2.1.0, json5@0.5.0)
├── lru-cache@4.0.1 (pseudomap@1.0.2, yallist@2.0.0)
├── source-map@0.5.6
├── vue-template-compiler@2.0.1 (de-indent@1.0.2, entities@1.1.1)
├── postcss-selector-parser@2.2.1 (indexes-of@1.0.1, flatten@1.0.2, uniq@1.0.1)
├── consolidate@0.14.1 (bluebird@3.4.6)
├── postcss@5.2.4 (js-base64@2.1.9, supports-color@3.1.2, chalk@1.1.3)
└── js-beautify@1.6.4 (nopt@3.0.6, config-chain@1.1.11, mkdirp@0.5.1, editorconfig@0.13.2)

css-loader@0.25.0 node_modules/css-loader
├── object-assign@4.1.0
├── postcss-modules-extract-imports@1.0.1
├── postcss-modules-scope@1.0.2
├── postcss-modules-local-by-default@1.1.1
├── loader-utils@0.2.16 (big.js@3.1.3, emojis-list@2.1.0, json5@0.5.0)
├── postcss-modules-values@1.2.2 (icss-replace-symbols@1.0.2)
├── source-list-map@0.1.6
├── babel-code-frame@6.16.0 (js-tokens@2.0.0, esutils@2.0.2, chalk@1.1.3)
├── lodash.camelcase@3.0.1 (lodash._createcompounder@3.0.0)
├── css-selector-tokenizer@0.6.0 (fastparse@1.1.1, cssesc@0.1.0, regexpu-core@1.0.0)
├── postcss@5.2.4 (js-base64@2.1.9, supports-color@3.1.2, source-map@0.5.6, chalk@1.1.3)
└── cssnano@3.7.7 (decamelize@1.2.0, postcss-normalize-charset@1.1.0, postcss-minify-gradients@1.0.3, postcss-discard-empty@2.1.0, postcss-discard-duplicates@2.0.1, postcss-merge-idents@2.1.7, postcss-reduce-transforms@1.0.3, postcss-reduce-initial@1.0.0, defined@1.0.0, postcss-reduce-idents@2.3.0, postcss-convert-values@2.4.1, postcss-discard-comments@2.0.4, postcss-value-parser@3.3.0, postcss-minify-font-values@1.0.5, postcss-discard-overridden@0.1.1, postcss-ordered-values@2.2.2, postcss-merge-longhand@2.0.1, postcss-zindex@2.1.1, postcss-discard-unused@2.2.1, postcss-unique-selectors@2.0.2, postcss-minify-params@1.0.5, postcss-merge-rules@2.0.10, has@1.0.1, postcss-filter-plugins@2.0.2, postcss-minify-selectors@2.0.5, postcss-normalize-url@3.0.7, postcss-calc@5.3.1, postcss-colormin@2.2.1, postcss-svgo@2.1.5, autoprefixer@6.5.0)

webpack-dev-server@2.1.0-beta.8 node_modules/webpack-dev-server
├── connect-history-api-fallback@1.3.0
├── strip-ansi@3.0.1 (ansi-regex@2.0.0)
├── supports-color@3.1.2 (has-flag@1.0.0)
├── opn@4.0.2 (object-assign@4.1.0, pinkie-promise@2.0.1)
├── compression@1.6.2 (on-headers@1.0.1, vary@1.1.0, bytes@2.3.0, compressible@2.0.8, debug@2.2.0, accepts@1.3.3)
├── express@4.14.0 (escape-html@1.0.3, methods@1.1.2, range-parser@1.2.0, parseurl@1.3.1, etag@1.7.0, vary@1.1.0, array-flatten@1.1.1, utils-merge@1.0.0, cookie-signature@1.0.6, content-type@1.0.2, encodeurl@1.0.1, merge-descriptors@1.0.1, fresh@0.3.0, content-disposition@0.5.1, cookie@0.3.1, path-to-regexp@0.1.7, serve-static@1.11.1, depd@1.1.0, qs@6.2.0, on-finished@2.3.0, debug@2.2.0, finalhandler@0.5.0, proxy-addr@1.1.2, accepts@1.3.3, type-is@1.6.13, send@0.14.1)
├── webpack-dev-middleware@1.8.4 (path-is-absolute@1.0.1, range-parser@1.2.0, mime@1.3.4, memory-fs@0.3.0)
├── spdy@3.4.3 (http-deceiver@1.2.7, handle-thing@1.2.5, select-hose@2.0.0, debug@2.2.0, spdy-transport@2.0.15)
├── serve-index@1.8.0 (escape-html@1.0.3, parseurl@1.3.1, batch@0.5.3, http-errors@1.5.0, mime-types@2.1.12, accepts@1.3.3, debug@2.2.0)
├── sockjs@0.3.18 (uuid@2.0.3, faye-websocket@0.10.0)
├── sockjs-client@1.1.1 (inherits@2.0.3, json3@3.3.2, debug@2.2.0, url-parse@1.1.4, faye-websocket@0.11.0, eventsource@0.1.6)
├── yargs@4.8.1 (decamelize@1.2.0, get-caller-file@1.0.2, lodash.assign@4.2.0, y18n@3.2.1, which-module@1.0.0, set-blocking@2.0.0, window-size@0.2.0, require-main-filename@1.0.1, require-directory@2.1.1, cliui@3.2.0, yargs-parser@2.4.1, string-width@1.0.2, os-locale@1.4.0, read-pkg-up@1.0.1)
└── http-proxy-middleware@0.17.2 (is-glob@3.0.0, http-proxy@1.15.1, micromatch@2.3.11, lodash@4.16.4)

webpack@2.1.0-beta.22 node_modules/webpack
├── object-assign@4.1.0
├── interpret@1.0.1
├── clone@1.0.2
├── async@1.5.2
├── tapable@0.2.4
├── supports-color@3.1.2 (has-flag@1.0.0)
├── loader-utils@0.2.16 (big.js@3.1.3, emojis-list@2.1.0, json5@0.5.0)
├── loader-runner@2.2.0
├── source-map@0.5.6
├── mkdirp@0.5.1 (minimist@0.0.8)
├── acorn@3.3.0
├── enhanced-resolve@2.3.0 (graceful-fs@4.1.9)
├── memory-fs@0.3.0 (errno@0.1.4, readable-stream@2.1.5)
├── webpack-sources@0.1.2 (source-list-map@0.1.6)
├── uglify-js@2.6.4 (async@0.2.10, uglify-to-browserify@1.0.2, yargs@3.10.0)
├── yargs@4.8.1 (get-caller-file@1.0.2, lodash.assign@4.2.0, decamelize@1.2.0, y18n@3.2.1, which-module@1.0.0, set-blocking@2.0.0, window-size@0.2.0, require-main-filename@1.0.1, require-directory@2.1.1, yargs-parser@2.4.1, cliui@3.2.0, os-locale@1.4.0, string-width@1.0.2, read-pkg-up@1.0.1)
├── node-libs-browser@1.0.0 (string_decoder@0.10.31, https-browserify@0.0.1, tty-browserify@0.0.0, path-browserify@0.0.0, punycode@1.4.1, constants-browserify@1.0.0, os-browserify@0.2.1, process@0.11.9, assert@1.4.1, domain-browser@1.1.7, querystring-es3@0.2.1, timers-browserify@1.4.2, stream-browserify@2.0.1, events@1.1.1, vm-browserify@0.0.4, util@0.10.3, readable-stream@2.1.5, console-browserify@1.1.0, url@0.11.0, http-browserify@1.7.0, buffer@4.9.1, browserify-zlib@0.1.4, crypto-browserify@3.11.0)
└── watchpack@1.1.0 (graceful-fs@4.1.9, chokidar@1.6.0, async@2.0.0-rc.4)

babel-core@6.17.0 node_modules/babel-core
├── slash@1.0.0
├── path-exists@1.0.0
├── path-is-absolute@1.0.1
├── shebang-regex@1.0.0
├── babel-messages@6.8.0
├── babel-template@6.16.0
├── private@0.1.6
├── babel-helpers@6.16.0
├── convert-source-map@1.3.0
├── source-map@0.5.6
├── babylon@6.11.4
├── debug@2.2.0 (ms@0.7.1)
├── minimatch@3.0.3 (brace-expansion@1.1.6)
├── babel-types@6.16.0 (to-fast-properties@1.0.2, esutils@2.0.2)
├── babel-code-frame@6.16.0 (js-tokens@2.0.0, esutils@2.0.2, chalk@1.1.3)
├── babel-generator@6.17.0 (jsesc@1.3.0, detect-indent@3.0.1)
├── babel-traverse@6.16.0 (globals@8.18.0, invariant@2.2.1)
├── json5@0.4.0
├── lodash@4.16.4
├── babel-register@6.16.3 (home-or-tmp@1.0.0, source-map-support@0.4.3, mkdirp@0.5.1, core-js@2.4.1)
└── babel-runtime@6.11.6 (regenerator-runtime@0.9.5, core-js@2.4.1)

babel-preset-es2015@6.16.0 node_modules/babel-preset-es2015
├── babel-plugin-transform-es2015-function-name@6.9.0 (babel-types@6.16.0, babel-helper-function-name@6.8.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-parameters@6.17.0 (babel-helper-get-function-arity@6.8.0, babel-helper-call-delegate@6.8.0, babel-template@6.16.0, babel-types@6.16.0, babel-traverse@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-modules-commonjs@6.16.0 (babel-plugin-transform-strict-mode@6.11.3, babel-template@6.16.0, babel-types@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-shorthand-properties@6.8.0 (babel-types@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-modules-umd@6.12.0 (babel-template@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-modules-systemjs@6.14.0 (babel-template@6.16.0, babel-helper-hoist-variables@6.8.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-arrow-functions@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-block-scoping@6.15.0 (babel-types@6.16.0, babel-template@6.16.0, babel-traverse@6.16.0, lodash@4.16.4, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-typeof-symbol@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-for-of@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-unicode-regex@6.11.0 (regexpu-core@2.0.0, babel-helper-regex@6.9.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-spread@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-duplicate-keys@6.8.0 (babel-types@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-object-super@6.8.0 (babel-helper-replace-supers@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-modules-amd@6.8.0 (babel-template@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-computed-properties@6.8.0 (babel-template@6.16.0, babel-helper-define-map@6.9.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-literals@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-template-literals@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-block-scoped-functions@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-check-es2015-constants@6.8.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-destructuring@6.16.0 (babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-sticky-regex@6.8.0 (babel-helper-regex@6.9.0, babel-types@6.16.0, babel-runtime@6.11.6)
├── babel-plugin-transform-es2015-classes@6.14.0 (babel-helper-replace-supers@6.16.0, babel-messages@6.8.0, babel-helper-optimise-call-expression@6.8.0, babel-helper-function-name@6.8.0, babel-helper-define-map@6.9.0, babel-template@6.16.0, babel-types@6.16.0, babel-traverse@6.16.0, babel-runtime@6.11.6)
└── babel-plugin-transform-regenerator@6.16.1 (private@0.1.6, babel-types@6.16.0, babel-runtime@6.11.6)
~/workspace/vue/my-project $

すこし時間かかりましたが入りました。

cloud9で実行する場合、サーバの設定が必要ですのでします。

package.jsonのscripts の devにIPとポートの設定--host 0.0.0.0 --port 8080を追加します。


変更後_package.json

  "scripts": {

"dev": "cross-env NODE_ENV=development webpack-dev-server --open --inline --hot --host 0.0.0.0 --port 8080",


最後にサーバーを起動:npm run dev

~/workspace/vue/my-project $ npm run dev

> my-project@ dev /home/ubuntu/workspace/vue/my-project
> cross-env NODE_ENV=development webpack-dev-server --open --inline --hot --host 0.0.0.0 --port 8080

http://0.0.0.0:8080/
webpack result is served from /dist/
content is served from /home/ubuntu/workspace/vue/my-project
404s will fallback to /index.html

では確認してみましょう。各自の環境に合わせてページにアクセスします。

https://<プロジェクト名>-<ユーザ名>.c9users.io/index

画面:

こんなんでました。

ソースはこんなんでした。最初にいったようにテンプレート・ロジック・スタイルがすべて1つのファイルに入ってます。

cloud9で開くときはエディタタブ右下にあるTextをクリックしてhtmlに変えるとハイライトがいい感じに出ます。


App.vue

<template>

<div id="app">
<img src="./assets/logo.png">
<h1>{{ msg }}</h1>
</div>
</template>

<script>
export default {
data () {
return {
msg: 'Hello Vue!'
}
}
}
</script>

<style>
body {
font-family: Helvetica, sans-serif;
}
</style>


App.vueの呼び出し側のindex.htmlはこんなの。中で使ってる/dist/build.jsはdevモードだとはアクセス時にビルドして、そのまま返しているようです。プロジェクト内に生成されてませんでした。


index.html

<!DOCTYPE html>

<html lang="en">
<head>
<meta charset="utf-8">
<title>my-project</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>


でこっちが実際のブラウザが表示してるDOM


実行時.html

<html lang="en">

<head>
<meta charset="utf-8">
<title>my-project</title>
<style type="text/css">
body {
font-family: Helvetica, sans-serif;
}
</style>
</head>
<body>
<div id="app">
   <img src="/dist/logo.png?82b9c7a5a3f405032b1db71a25f67021">
   <h1>Hello Vue!</h1>
  </div>
<script src="/dist/build.js"></script>
</body>

</html>


div内がテンプレートで置き換わってる他、画像ソースにキャッシュクリアがついてたり、ヘッダにスタイルが追加されてたり、いろいろやってるみたいですね。

以上になります。個人的にはコンポーネントはテンプレート・ロジック・スタイルを並べて編集したいので、ファイルを分けてフォルダ単位で管理したほうが、変更楽だと思うんですけど、どうなんでしょうね。まぁ1つのファイルを3つのエディタで開けば似たようなことはできるんですけど。1エディタで編集しづらいくらいにでかいのは、コンポーネントを小分けにして設計見直せってことかもしれませんね。