- 投稿日:2021-01-16T23:55:31+09:00
nuxtで書いたコードをGASで使えるよう変換
概要
- nuxtで作成したファイル(vueコンポーネント形式)をGASで利用できる形(x-template形式)に変換する
- これ自体がnuxtで動くプログラム。個人で使うなら自分のPCでローカルホストを立ち上げ、変換されたコードをコピペして使えば良い。
開発背景
- GASでフロントサイドを書くにあたって、GASのエディタはお世辞にも使いやすいとは言えません(最近のアップデートでだいぶ使いやすくはなりましたが)
- 多分GAS開発者の多くがしているように、claspで作成してGASにプッシュする方法がありますが、claspプッシュしてWebページをリロードして、、、というのは地味に面倒ですし、エラーが見つけにくいという欠点もあります。
- そこで、私はnuxtでUIをある程度作ってから、GASのhtmlファイルにコピーする方法をとっています。
- nuxtで作ったファイルをそのままコピーできれば良いのですが、nuxtはコンポーネントを.vue形式で作成するのに対して、GASでは.html形式にする必要があること、コンポーネントの書き方はnuxtは〜とexhast defaultに対してGASではx-templateを使った書き方であるなど、いくつかの修正する必要があります。
- もともとはこれらの作業を手でやっていましたが、コンポーネントファイルが多くなってくると面倒なので、プログラム化しました。
設計
ユーザー操作
- ブラウザでnuxtアプリのフォルダをアップすると、html形式にしてダウンロードできるようにします。
- テキストの編集は全てjavascriptで実装しました。
nuxtとGASの違い
- ファイル形式について、nuxtではコンポーネントファイルが.vue形式、一方でGASでは.html形式
- コンポーネントの書き方について、nuxtではHTMLに相当する部分をで括りjavascriptをexport defaultで読み取れるようにしている。一方でGASのhtmlファイルでは、HTMLの部分を
<script type="text/x-template">
で括り、ローカルコンポーネントを変数に入れて親コンポーネントで読み取れるようにしているnuxt → GASへの変換
componentsのファイル
- ファイル名をsomething.vueからsomething.htmlに
<template>
の部分を<script type="text/x-template" id="something">
に- export default"を"const something =" に
- template = "#something", を追加
pagesのファイル
1〜4まではcomponentsと同じ
- import ChildComponent from "~/components/ChildComponent.vue"を削除
layoutsのファイル
- 私の開発ではSPAで作成しており、layouts/index.htmlは以下のような構造
<!DOCTYPE html> <html> <head> <base target="_top"> <?!= include("config") ?> </head> <body> <?!= include("components/EditComponent") ?> <?!= include("components/ImportMailList") ?> <?!= include("components/MailListHead") ?> <?!= include("components/MailPreview") ?> <?!= include("components/VarConfig") ?> <?!= include("pages/mailer") ?> <div id="app"></div> <script> new Vue({ vuetify: vuetify, render: h => h(mailer) }).$mount("#app") </script> </body> </html>工夫点
フォルダのアップロードとファイルの処理
- フォルダのアップロードにはinputタグにwebkitdirectry属性を追加する
- webkitdirectoryでフォルダをアップした後で、各ファイルを処理する方法は以下参照
<template> <input type="file" @change="upload($event)" webkitdirectory> </template> <script> (vue methods) async upload(event){ //ファイル一覧の取得と各ファイルの処理 const files = event.target.files for(const file of files){ //ファイルパスの取得 const path = file.webkitRelativePath; //ファイルの読み取り等はPromiseを用いて同期処理すること const text = await this.editFile(file) } }, editFile(file){ return new Promise((resolve,reject)=>{ const reader = new FileReader() reader.readFileAsText() reader.onload = function(e){ const text = e.target.result resolve(text) } }) } </script>nuxtのファイル一覧から必要なファイルの絞り込み
- nuxtのフォルダをアップすると、2万強のファイルがアップされる。
- そのうち、必要なvueファイルを絞り込むには以下のようにする
const path = file.webkitRelativePath; //不要なファイルをフィルタリング if(!path.includes(".vue"))continue; if(path.includes(".nuxt"))continue; if(path.includes("node_modules"))continue;
- 投稿日:2021-01-16T22:14:46+09:00
Django+Vue.js の開発環境を docker-compose で構築する(2)
この記事は前回からの続きです
前回:Django+Vue.js の開発環境を docker-compose で構築する(1)
前回は、Vue のコンテナを立ち上げてプロジェクトを作成し、GitHub でのレポジトリ管理をフロントエンド(Vue)とバックエンド(Django)に分けました。
今回やりたいこと
今回は、nginx のリバースプロキシを設定し、Vue のスタート画面を見るところまでやっていきます。
手順
- Vue のプロジェクトをビルドする
docker-compose.dev.yml
を編集するapp_nginx.conf
を編集する1. Vue のプロジェクトをビルドする
まずは Vue のプロジェクトをビルドします。まだなんにも作ってないけどね。
$ docker-compose -f docker-compose.dev.yml run vue npm run build正しくビルドされれば、Vue のディレクトリに
dist
というディレクトリができます。2.
docker-compose.dev.yml
を編集する次に、コンテナの
/frontend
に./src/frontend
をマウントさせるように、docker-compose.dev.yml
の nginx セクションを編集します。docker-compose.dev.yml(抜粋)nginx: image: nginx:1.17 restart: unless-stopped container_name: nginx networks: - django_net ports: - "80:80" volumes: - ./nginx/conf:/etc/nginx/conf.d - ./nginx/uwsgi_params:/etc/nginx/uwsgi_params - ./static:/static - ./src/frontend:/frontend # 追加 depends_on: - python3.
app_nginx.conf
を編集する最後に、nginx を次のとおりに設定します。
./nginx/conf/app_nginx.confupstream django { ip_hash; server python:8001; # uWSGI で Django と nginx とが通信するためのポート server vue:3000; # Vue と nginx とが通信するためのポート # 追加 } server { listen 80; # 待ち受けポート server_name 127.0.0.1; charset utf-8; location /static { alias /static; } client_max_body_size 75M; location / { # 追加 root /frontend/dist; # 追加 } # 追加 location /apiv1/ { # 追加 uwsgi_pass django; # 追加 include /etc/nginx/uwsgi_params; # 追加 } location /admin/ { # 追加 uwsgi_pass django; # 追加 include /etc/nginx/uwsgi_params; # 追加 } # 追加 } # 追加 server_tokens off;要するに、
-/
へのアクセスは、/frontend/dist
にルーティング
-/static
へのアクセスは、./static
にルーティング
-/apiv1
と/admin
へのアクセスは、uwsgi 経由で Django にルーティング
とします。ちなみに、ngnix の待ち受けポートが 80 番になっているのは、私が Mac 上の VirtualBox で Ubuntu Server を動かしており、ホストの 8081 番とゲストの 80 番を接続しているからです。だから、Mac のブラウザで http://127.0.0.1:8081/ にアクセスすれば、開発中の画面が見られるってワケ。
関連:もう VirtualBox の設定で悩まない。そう、Vagrant ならね?動作確認
以上を設定し、コンテナを再起動してトップページにアクセスすると、無事に Vue のスタート画面を見ることができました。
- 投稿日:2021-01-16T22:10:45+09:00
Nuxt.js + Storybook導入で詰まった点の覚え書き
概要
既存のnuxt.jsにstorybookを導入しようとして、詰まった点をまとめます。
基本は公式ドキュメントの手順を参照環境
storybook : 6.1.14
nuxt.js: 2.9.2scssを読み込みたい
遭遇したのは2パターンでvueファイル上の
<style lang="scss">
内にあるscssと全体のscssファイルの読み込みである。大体全体のscssが読み込まれていない場合,vueファイル内で参照している変数がうまく読み取れず以下のようなエラーが出る。
SassError: Undefined variable: "$変数名".これを解決するためには
.storybook/main.js
で以下のようにwebpackの設定をしてあげると解決する。storybook/main.jsconst path = require('path'); const rootPath = path.resolve(__dirname, '../'); module.exports = { webpackFinal: async (config, { configType }) => { config.module.rules.push({ test: /\.scss$/, use: ['style-loader', 'css-loader', { loader: 'sass-loader', options: { // scssファイル読み込み prependData: ` @import "~/assets/scss/<scssファイル1>"; @import "~/assets/scss/<scssファイル2>"; ` } } ], include: rootPath }); return config; }, "stories": [ "../stories/**/*.stories.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials" ] }webpackのドキュメントだとadditionalDataになってるけどバージョンの問題だろうか?
参照しているvueのpathが~/xxxx.vueになっており、ファイルが見つからない。
Module not found: Error: Can't resolve '~xxxx`みたいなエラーが出てくる
これは
.storybook/main.js
に以下のような設定を追加追加することで解決できる。storybook/main.jsconst path = require('path'); const rootPath = path.resolve(__dirname, '../'); module.exports = { webpackFinal: async (config, { configType }) => { config.module.rules.push({ test: /\.scss$/, use: ['style-loader', 'css-loader', { loader: 'sass-loader', options: { prependData: ` @import "~/assets/scss/<scssファイル1>"; @import "~/assets/scss/mixins/<scssファイル2>"; ` } } ], include: rootPath }); config.resolve.alias['~'] = rootPath; return config; }, "stories": [ "../stories/**/*.stories.mdx", "../stories/**/*.stories.@(js|jsx|ts|tsx)" ], "addons": [ "@storybook/addon-links", "@storybook/addon-essentials" ] }
@
の場合はconfig.resolve.alias['@'] = rootPath;とすれば良い。
解決できなかった問題
Nuxtにはpluginとして任意のjsコードをインジェクトする機構が存在する。参考
これをstorybook上だと以下のようなエラーが出てinjectしてくれなかった。
_vm.<pluginでinjectされるはずの> is not a function良い方法があれば教えてもらえるとうれしい。
scssの対応を除いて概ねすんなりと導入できた。
nuxtと言いつつ大体webpackの設定周りだった。webpackは触りたくないなぁ。。。
- 投稿日:2021-01-16T21:38:35+09:00
vuetifyで「[Vue warn]: The .native modifier for v-on is only valid on components but it was used on <div>.」
起きたこと
私の場合はカレンダー・コンポーネントを使った時に発生しました。
起動はしますが、ブラウザ上でwarningが出ます。
[Vue warn]: The .native modifier for v-on is only valid on components but it was used on <div>.
解決方法
その1 vuetifyのバージョンをあげる
このwarningについてはGitHubでissueがあがっていて、解決済です。(v-iconでも発生するようです)
[Bug Report] warning with VueJS 2.6.11 · Issue #9999 · vuetifyjs/vuetify
[Bug Report] Button wrapper missing for faSvg clickable v-icons · Issue #10623 · vuetifyjs/vuetify修正のPRは↓で、v2.3.14でリリース済です。
というわけで、v2.3.14に上げれば発生しなくなります。
その2 warningを無視するコードを入れる
様々な事情でバージョンをあげるのが難しい場合、無理やり無視する事も可能です。(warningなので動作に影響は無いようです)
該当のコードはこちら。
Nuxtの場合は、pluginとして書いてあげるとわかりやすいです。
ignore-warning.tsconst ignoreWarnMessage = 'The .native modifier for v-on is only valid on components but it was used on <div>.'; Vue.config.warnHandler = function (msg, vm, trace) { // `trace` is the component hierarchy trace if (msg === ignoreWarnMessage) { msg = null; vm = null; trace = null; }該当のwarningメッセージを握りつぶします。
- 投稿日:2021-01-16T11:44:03+09:00
初心者限定!!Vueで横幅(width)の変化を検知する方法
今回は、タイトルにも書いてる通りwindowの横幅の変化を検知したいと思います!!!
長ったらしい話はせずにもうコードを書いていきますね!
まず、初めにdataオブジェクトで
currentWidth
というプロパティを宣言し、横幅が変化するたびに呼び出す関数を設定していきます。App.vue<script> export default { data() { return { currentWidth: window.innerWidth, } }, methods: { calculateWindowWidth() { // 横幅を取得する関数 this.windowWidth = window.innerWidth } } } </script>初期値として、
window.innerWidth
を設定しておきます。次に、DOM要素と紐づけられた後に行う関数
mounted
、DOM要素が消去される前の関数beforeDestroy
を用いて、横幅の変更を検知します。App.vue<script> export default { data() { return { currentWidth: window.innerWidth, } }, mounted() { // 横幅の変更を検知 window.addEventListener('resize', this.calculateWindowWidth) }, beforeDestroy() { // 横幅の変更を検知 window.addEventListener('resize', this.calculateWindowWidth) }, methods: { calculateWindowWidth() { // 横幅を取得する関数 this.currentWidth = window.innerWidth } } } </script>いかがだったでしょうか?
僕は、最初に
computed
で行ってしまい横幅の変更を検知してくれませんでした。最初は
computed
便利だな~って思ってたんですけど、最近使い方が難しいことに気づきました。なんとなく出来たので良しとします。
以上、「初心者限定!!Vueで横幅(width)の変化を検知する方法」でした!
良かったら、LGTM、コメントお願いします。
また、何か間違っていることがあればご指摘頂けると幸いです。
他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!
Thank you for reading
- 投稿日:2021-01-16T11:31:31+09:00
【Vue】親から孫へとPropsを受け渡す方法
はじめに
本記事へのアクセスありがとうございます。
Atomic designの実装においてPropsによるデータの受け渡しが多発したので、親コンポーネントから孫コンポーネントまでの一連のデータの流れを備忘録も兼ねて記事に残したいと思います。
では、さっそく見ていきましょう。親から孫コンポーネントへ
親コンポーネント
<template> <div> <child :parent-to-child-prop="sendData" /> </div> </template> <script> export default { components: { Child: () => import('@/components/Child') }, data() { return { sendData: '親から孫へ' } } } </script>子コンポーネント
<template> <div> <grand-child :child-to-grand-child-prop="parentToChildProp"/> </div> </template> <script> export default { props: { parentToChildProp: { type: String, default: '' } }, components:{ GrandChild: () =>import('@/components/GrandChild') } } </script>孫コンポーネント
<template> <div> {{ childToGrandChildProp }} </div> </template> <script> export default { props: { childToGrandChildProp: { type: String, default: '' } } } </script>おわりに
propsを用いるときはtypeとdefaultは設定しておきましょう。
また、テンプレート内にcomponentを書くときはケバブケースでpropsで貰って使うデータはキャメルケースで書くようにしています。
誰かのお役に立てれば幸いです?♂️
- 投稿日:2021-01-16T00:50:35+09:00
Vue.js + TypeScript で@Componentをつけ忘れていたら、変更内容がうまく反映されずにはまった話
Vue.js + TypeScript で開発をしている時に、
Props
を更新したり、template部分を変更しても、うまく反映され図にかなりはまってしまい、修正に時間がかかってしまった。結果、
@Component
をつけたら、全てが解決した。
なぜ、解決したかも踏まえた、勉強してしっかりまとめておこうと思う。発生事象
Vue.js + TypeScript で、以下の形式で
.vue
ファイルを使用して開発を行っていた。@Component({}) export default class MyComponent extends Vue { ... }そうすると、以下のような問題が発生した。
data
で設定した場合は画面に反映されるが、Prop
で設定すると画面に反映されない。template
で設定した内容が反映されない。解決内容
調べて見ると、共通点として、
@Component
を指定しているもののみが上記の事象が反映していることに気づく。
@Component
をつけてみると、全てがうまくいった。。。公式ドキュメントを見ると、
@Component
をつけることは必須とのことでした。。。
https://jp.vuejs.org/v2/guide/typescript.htmlすごいシンプルなことだったけど、すごいはまって、1-2日使ってしまったので、メモがてら残しておきます。
時間があれば、この辺りの仕組みも少し勉強したい。。。参考サイト