Vue CLI も Rails+Webpacker も使わずに、Vue.js(単一ファイルコンポーネント)を試す方法です。
スクラッチから作るのが好きな人、WebpackとBabelが吐いたコードを眺めたい人はどうぞ。
ソースコード: https://github.com/kazubon/webpack-babel-vuejs
準備
てきとうなディレクトリを作り、yarnで必要なモジュールをインストールします。
% mkdir scratch && cd scratch
% yarn add @babel/core @babel/preset-env babel-loader core-js vue vue-loader vue-template-compiler webpack webpack-cli
webpack-dev-server は入れずに手動でコンパイルします。
(2020-09-28更新: dependencies と devDependencies を分けるのやめ。)
最終的なディレクトリとファイルの配置は次のようになります。
- dist
- app.js
- app.js.map
- node_modules
- src
- app.js
- hello.vue
- babel.config.js
- index.html
- package.json
- wbpack.config.js
- yarn.lock
Vueアプリケーション
HTMLと簡単なVueアプリケーションを書きます。特に説明は要らないかと思います。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>てすと</title>
<script src="dist/app.js"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
import Vue from 'vue';
import Hello from './hello.vue';
document.addEventListener('DOMContentLoaded', () => {
new Vue(Hello).$mount('#app');
});
<template>
<div>
<h1>{{message}}</h1>
<p><input v-model="message"></p>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
};
},
created() {
this.message = 'hello';
}
}
</script>
webpackでコンパイル
webpack.config.js を書きます。src/app.js が dist/app.js に出力されるようにします。
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const path = require('path');
const env = process.env.NODE_ENV || 'development';
module.exports = {
entry: './src/app.js',
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist'),
},
mode: env,
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader'
}
]
},
plugins: [
new VueLoaderPlugin()
]
}
2020-12-11 追記: 単一ファイルコンポーネントではなく、HTMLに埋め込まれたテンプレートを使うには、コンパイラ入りのVue.jsが必要です。コンパイラ入りを使うには、resolve.aliasを追加して、vue.esm.js を指定します(参照: さまざまなビルドについて)。
module.exports = {
// 略
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
}
package.json に scripts.build を追加すると、yarnコマンドでwebpackを呼び出せます。
{
"scripts": {
"build": "webpack --config=webpack.config.js"
},
"dependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"babel-loader": "^8.1.0",
"core-js": "^3.6.5",
"vue": "^2.6.12",
"vue-loader": "^15.9.3",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12"
}
}
yarn build とすると、webpackが dist/app.js を生成します。
% yarn build
環境変数 NODE_ENV を production にすると、本番環境用に圧縮された dist/app.js ができます。
% NODE_ENV=production yarn build
index.html を ブラウザーで開いてVueアプリケーションが動けば成功です。
devtool オプション
さて、出来上がった dist/app.js を覗いてみますと、次のような感じで eval が埋め込まれていて、どう変換されたのかよく分からない。
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n//\n/* harmony ...
webpack.config.js で devtool オプションを指定すると、出力の形式を変えられるらしい。どういう値を指定できるかは、Devtool | webpack に一覧があります。とりあえず source-map を指定します。
module.exports = {
// 略
devtool: 'source-map',
// 略
}
コンパイルすると dist/app.js が読めるようになります。
/* harmony default export */ __webpack_exports__["default"] = ({
data() {
return {
message: ''
};
},
@babel/preset-envの設定
dist/app.js をよく見ると、アロー関数などES2015のシンタックスがそのまま埋め込まれています。Babelを使ってIE 11対応の形に変換したい。
document.addEventListener('DOMContentLoaded', () => {
new vue__WEBPACK_IMPORTED_MODULE_0__["default"](_hello_vue__WEBPACK_IMPORTED_MODULE_1__["default"]).$mount('#app');
});
webpack.config.js で .js の loader の設定を次のように変え、@babel/preset-env を指定します。
module.exports = {
// 略
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
// 略
}
コンパイルしたものを見ると、アロー関数がfunctionに変換されていました。
document.addEventListener('DOMContentLoaded', function () {
new vue__WEBPACK_IMPORTED_MODULE_0__["default"](_hello_vue__WEBPACK_IMPORTED_MODULE_1__["default"]).$mount('#app');
});
Babel の設定ファイル babel.config.js を使うこともできます。これをアプリケーションのルートに置いておくと設定が反映されます。
api.cacheの設定をしないとエラーが出るので、api.cache(true)
としてあります。この設定の意味は分かりません。
module.exports = api => {
api.cache(true);
return {
presets: [
[
"@babel/preset-env",
{
targets: { ie: "11" },
useBuiltIns: "entry",
corejs: 3
}
]
]
}
}
webpack.config.js のほうは元に戻します。
module.exports = {
// 略
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
loader: 'babel-loader'
}
]
},
// 略
}
preset_envのマニュアル に従い、IE 11がサポートしていない新しいメソッドを使うときは、2つのモジュール core-js/stable と regenerator-runtime/runtime をインポートしておきます。
import "core-js/stable";
import "regenerator-runtime/runtime";
import Vue from 'vue';
import Hello from './hello.vue';
document.addEventListener('DOMContentLoaded', () => {
new Vue(Hello).$mount('#app');
});
2020-03-19追記: Vue.jsはデフォルトでIE 11に対応しているので、この程度のサンプルなら core-js/stable と regenerator-runtime/runtime は要りません。IEが対応していないJavaScriptのメソッドや組み込みクラスを使うときは core-js、asyncとawaitを使うときは regenerator-runtime が必要です。
以上です。
Vue 3版はこちら: スクラッチからWebpack+Babel+Vue 3を使う
参考にしたページ: