くりーむわーかー

プログラムとか。作ってて ・試しててハマった事など。誰かのお役に立てば幸いかと。 その他、いろいろエトセトラ。。。

2018年12月

Vueのrender(描画関数)でJSXでv-modelを使いたい

Vueは素晴らしいと思うのですが、公式のこの辺に書いてある通り、大量なv-ifとか使わないとつらい場合等、純粋なJavaScriptのロジックで書きたくなる事はやっぱある。

その時の対応としてrender()をVueで用意してくれているのですが、いかんせん、なかなか書きにくい感じになっている。それにも対応してくれていて、JSXで書けるようにbabelのプラグインがある。

で、JSXで書けるんだけど、v-modelがまるで効かない。公式的にはv-modelは対応してないから自分でロジック作れって書いてはある。でもやっぱVueで入力系のコンポーネント作るときはv-model使いたい。

探してみると、babel-plugin-jsx-v-modelっていうプラグインで出きるっぽい、入れてみようかなーで公式のVue-Cliのソースとかみてたら↓の状態になってた。

sample

おや?つーか、そもそもプラグイン入ってるの?つか、コメントアウトされておる。。。

そしたら、Readmeに↓で書いてあった。

sample2

あらん。Babel7への対応が出来てないから一時的に無効にするとさ。残念。

復活を期待しつつ、v-modelを別の形で実装しておくしかあるまい。

Vue CLI 3 のWebPackの設定

ちょっと独り言。

公式のココに書いてあるけど、vue cli3のinspectが凄く便利だった。

vue inspect > output.js

で、vue cliで作ったプロジェクトのwebpackの設定が全部見れる。

「@」ってaliasでそういう設定してたのねとか。

設定の上書きするのにもこれ見ないとどうすればいいかわかんないですね。

babel thisがundefinedになるやつ

GitHubのリポジトリにあるソースを参考にして、

別のプロジェクトに組み込もうとかした時に、

ちょっと昔のソースだと即時関数的に↓の感じのコードになってる場合。

(function(root,factory){
  //code
}(this,function(){
  //code
}));

bable7以上だと、引数のthisがundefinedになって動かなくなる。

で、色々対応方法調べてみたら、下のがとりあえずの回避方法。

.babelrcの中に下の感じで対象のjsファイルを書く。

module.exports = {
  overrides: [
    {
      test: "./src/utils/hoge.js",
      sourceType: "script"
    },
    {
      test: "./src/utils/fuga.js",
      sourceType: "script"
    }
  ]
};

デフォだとmoduleとして読み込んでるみたいで、export defaultで定義しておかないとダメになるって事なんかな?で、それをmoduleじゃなくてscriptファイルとして読み込めっていう設定なのかしら。いまいち分かってない。

本来はソースをexport default的なやつに直した方がいいんじゃないかと思う。今時の作り方で言えば、即時関数自体やめた方がよいのかしらね。

Vueで「babel.config.js」使ってる場合も同様に下の感じで書く。

module.exports = {
  presets: ["@vue/app"],
  overrides: [
    {
      test: "./src/utils/hoge.js",
      sourceType: "script"
    },
    {
      test: "./src/utils/fuga.js",
      sourceType: "script"
    }
  ]
};

gulpでscssのビルド構成を考える(element-ui)

scssを利用して作成するのにどういう構成がいいのかな~って考えてたんだけど、

自分アホなので、頭使うよりここは有名なリポジトリからパクろうと思い立った。

という事で「element-ui」でやってるやり方を参考にしよう。

element-uiのソースを読んでみる。

まず、ビルドはどうしているのだろうか。Makefileがあるから、

きっとmake ***で何かしてるんだろう。というわけでMakefile

# build all theme
build-theme:
	npm run build:theme

install:
	npm install

install-cn:
	npm install --registry=http://registry.npm.taobao.org

・・・・

お。build-themeっていうのがある。多分これっぽい。

npm run build:themeのエイリアスですか。

そしたら、package.json見てみましょ。

"scripts": {
    "bootstrap": "yarn || npm i",
    "build:file": "node build/bin/iconInit.js & node build/bin/build-entry.js & node build/bin/i18n.js & node build/bin/version.js",
    "build:theme": "node build/bin/gen-cssfile && gulp build --gulpfile packages/theme-chalk/gulpfile.js && cp-cli packages/theme-chalk/lib lib/theme-chalk",
    "build:utils": "cross-env BABEL_ENV=utils babel src --out-dir lib --ignore src/index.js",

node build/bin/gen-cssfileしてから

gulp build --gulpfile packages/theme-chalk/gulpfile.jsでビルドして、

cp-cli packages/theme-chalk/lib lib/theme-chalkでリリース用のディレクトリにコピーって流れかな?

gen-cssfileは何してるのかしら。

var fs = require('fs');
var path = require('path');
var Components = require('../../components.json');
var themes = [
  'theme-chalk'
];
Components = Object.keys(Components);
var basepath = path.resolve(__dirname, '../../packages/');

function fileExists(filePath) {
  try {
    return fs.statSync(filePath).isFile();
  } catch (err) {
    return false;
  }
}

themes.forEach((theme) => {
  var isSCSS = theme !== 'theme-default';
  var indexContent = isSCSS ? '@import "./base.scss";\n' : '@import "./base.css";\n';
  Components.forEach(function(key) {
    if (['icon', 'option', 'option-group'].indexOf(key) > -1) return;
    var fileName = key + (isSCSS ? '.scss' : '.css');
    indexContent += '@import "./' + fileName + '";\n';
    var filePath = path.resolve(basepath, theme, 'src', fileName);
    if (!fileExists(filePath)) {
      fs.writeFileSync(filePath, '', 'utf8');
      console.log(theme, ' 创建遗漏的 ', fileName, ' 文件');
    }
  });
  fs.writeFileSync(path.resolve(basepath, theme, 'src', isSCSS ? 'index.scss' : 'index.css'), indexContent);
});

components.jsonを読み込んで何やらループしてる模様。

components.jsonは何かいてあるのかしら

{
  "pagination": "./packages/pagination/index.js",
  "dialog": "./packages/dialog/index.js",
  "autocomplete": "./packages/autocomplete/index.js",
  "dropdown": "./packages/dropdown/index.js",
  "dropdown-menu": "./packages/dropdown-menu/index.js",
  "dropdown-item": "./packages/dropdown-item/index.js",
  "menu": "./packages/menu/index.js",

element-uiの各コンポーネントの名前定義っぽいですね。

コンポーネントの一覧でループして、それぞれのコンポーネントのSCSSを読み込むための

@import "./dialog.scss";

↑みたいなのを一個づつ書いてindex.scssっていうファイルを作成してる感じかな?

次は、gulp build --gulpfile packages/theme-chalk/gulpfile.js

'use strict';

var gulp = require('gulp');
var sass = require('gulp-sass');
var autoprefixer = require('gulp-autoprefixer');
var cssmin = require('gulp-cssmin');

gulp.task('compile', function() {
  return gulp.src('./src/*.scss')
    .pipe(sass.sync())
    .pipe(autoprefixer({
      browsers: ['ie > 9', 'last 2 versions'],
      cascade: false
    }))
    .pipe(cssmin())
    .pipe(gulp.dest('./lib'));
});

gulp.task('copyfont', function() {
  return gulp.src('./src/fonts/**')
    .pipe(cssmin())
    .pipe(gulp.dest('./lib/fonts'));
});

gulp.task('build', ['compile', 'copyfont']);

ほうほう。gulp-sassとgulp-autoprefixerとgulp-cssminを使ってる模様。

gulp-sassはscssのコンパイラでしょ。

autoprefixerはベンダプレフィクスつけるやつよね。

cssminはcssのミニファイズしてくれるやつかな。

あと、Webフォントのコピーをしてる感じかー。

compileでsrc配下の.scssファイルを丸ごとビルドする感じなのね。

なるほろ。なるほろ。

element-ui使うときって↓とかでcss一個しか読んでないけど、こうやって各コンポーネントのcssを一個にまとめてたのね。なるほろ。なるほろ。

<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">

ソース読んで見ると、「gen-cssfile.js」で「theme-chalk」以外のテーマも作れるようにしてるっぽいですね。複数テーマを準備する予定だったのかしらね。というかここいじれば自分でテーマ作ってビルドできるってことか。テーマのカスタマイズ自体は公式にやり方書いてあるけど、根本的に変える場合はここでやるのかしらね。勉強になります。

自分みたいな凡人は先人・天才に頼らないとやっていけませんね。

Webシステムのスクリーンショットをjavascriptとか使ってとる

Webの業務システムなんかを作ってるとシステムのスクリーンショットを撮りたいっていう要望がだいたいあがる。PrintScreenでがんばってで終わればいいんだけど、システムの中でやってとか、まーお客さんの環境によってはキャプチャが動かせなかったり色々あるので、システムでやらないとまずい場合がある。あと、スクロールするページの場合、一回のスクショで全体を撮りたいみたいな要望もあったりする。

そん時にどうやるかという事。VueとかNuxtで作ったSPAなアプリとかでやりたい場合とかも。

最近のやり方としては↓の感じなのかなーと思う。

  1. ブラウザのネイティブの機能を使う
  2. javascriptのライブラリを使う
  3. サーバ側で処理する

ブラウザのネイティブの機能を使う

これはChrome前提。自分は使ったことないんだけど、↓あたりのものを使えばいけそう。

Chrome拡張を使うか自分で作ってやる感じのやり方。

javascriptのライブラリを使う

javascriptでやる場合はだいたい下記を使うんじゃないだろうか。

htmlをcanvasにレンダリングするのをjavascriptで作った変態(褒め言葉)モジュール。スターの数とかえらいことになってるの。相当使えるんだけど、100%の再現率じゃない。対応してないstyleの属性とかもあって、ブラウザで見えてるものとはちょっと変わっちゃう。スクショの用途にもよるけど、ある程度の再現が出来てない場合は使えない。あと、ここ半年くらい更新されて無いのでちょっと心配。

でも、特定のDOMだけレンダリングしないとか出来て、例えば個人情報的にこの場所は非表示にしてスクショ撮りたいとかの要望にも対応出来たりする。

サーバ側で処理する

で、自分はこれがいいと思う。サーバにブラウザで表示されてるHTMLのDOMを丸ごと送って、サーバ側で、サーバのchromeなんかで、レンダリングしてスクショ撮る感じ。

今見えてる状態のHTMLを送りつけるので、VueとかNuxtとかのSPAでもちゃんと上手くいく。

で、ブラウザのエミュレータみたいなものが必要なんだけど、最近だとpuppeteer っていうのがすごく使える。Googleが作ってるOSSのものらしいですよ。

スクショ撮った後に、パスワードかけて圧縮してDLさせたりとか色々制御できるのでこのやり方が一番融通効くと思う。

で、やり方。

クライアント側
//現在のHTMLを丸ごと取得
const htmldoc = document.documentElement.cloneNode(true)
//スクリプトタグが邪魔なので全部消す
;[...htmldoc.querySelectorAll('script')].forEach(e => e.remove())
//HTML文字列を取得
const htmlstr = htmldoc.outerHTML
//サーバに送信
this.$axios
.post('http://hoge.fuga/api/save', { data: htmlstr })
.then(function() {
	console.log('OK')
})

サーバにHTMLの文字列丸ごと送ってサーバ側のローカルに保存。そしたらパペティア動かす。

ローカルのファイルを見る場合は↓の感じでやる。

サーバ側

"use strict";
const puppeteer = require("puppeteer");

(async () => {
  //centosで動かす場合は--no-sandboxのオプションをつけないと動かない
  const browser = await puppeteer.launch({
    args: ["--no-sandbox", "--disable-setuid-sandbox"]
  });
  //ブラウザの定義
  const page = await browser.newPage();
  //画面の大きさ指定
  page.setViewport({ width: 1600, height: 900 });
  //保存してあるファイルを読み込み
  await page.goto("file:///home/hogeuser/saved.html", {
    waitUntil: "networkidle0" //遅延ロード
  });
  //スクリーンショットをページ全体で取る場合
  await page.screenshot({ path: "example.png", fullPage: true });
  //PDFをA4で作る場合
  await page.pdf({ path: "test.pdf", format: "A4" });
  //ブラウザを閉じる
  await browser.close();
})();

パペティアの方で色々制御したりも出来るのであとは要件しだい。

ついでに、Webフォントとか使ってる場合、font-faceの指定のところとかサーバ側のローカルにしておけばスクショ側でもちゃんとWebフォントが反映される。

パペティア自体はe2eのテストに使ったり、色んなサイトを巡回したりする用途が普通なのかしらね。

ただ、ブラウザの一番外のスクロールなら「fullPage: true」付ければ全画面のスクショ撮ってくれんるんけど、中のDOMのスクロールはさすがに無理なので、必要ならその辺を展開してからサーバに送るとかが必要かな。

最近のプログラミング言語 流行り廃り(StackOverFlowのアンケート)

Googleトレンドで遊んでて、最近の言語はどんな感じなのかなって見てた。だいぶ偏見によった検索ワードですが、下記。

sample01

意外だったのがPythonがJava抜いてるじゃんってとこ。ついにJavaも終焉か・・・って事にはならないと思いますが、私的にはJavaは10年後にレガシーとか言われてそうな気がしている。

昔はPythonとかニッチ(死語?)な言語だと思ってましたが、割と来てるんだね。

最近どうなのか気になったので、StackOverFlowのアンケート結果(2018)を確認してみた。

アンケートの前提

回答:100,000人

地域的なとこ↓

sample02

インドとアメリカとヨーロッパが多そう?

仕事柄↓

03

フロントエンド・バックエンド・フルスタックがほとんどだけど、正直SEなんて、よっぽど特化してなければ、ほぼ3つのどれかにあてはまるよね。。。

あと、回答者のうち半分くらいは5年未満の経験者(仕事として)って事みたい。

若めの回答者が多いっていう認識でよろしいのかな?

良く使う言語

04

良く使うフレームワーク

05

JavaScriptを一番使うらしい。まー、今はほぼWeb系でしょうし。フロントエンドの人はそうなるでしょうね。フレームワークもJavaScript寄りのものが順当に上位。

個人的には.net Coreが割と上位に来てて意外だった。Spring抜いてんだね。C#好きとしてはなんかうれしい。VS2003あたりの.net(正確にはVisualStudio)はクソだと思ったけど、2008あたりから急激に良くなりましたよね。MSがOSSに寄ってきた感じがちょっとした。

まー、C#はVisualStudioありきの言語なのは否めませんが、それでも気持ちよく書けるのが素晴らしいと思う。半分はVSが良いって感じかもかも。

あと、Pythonもやっぱ来てるんだね。ほぼ機械学習・AI・データマイニング絡みだと思いますが、Pythonも書きやすくて好き。

今後数年はPythonとC#がバックエンド的には来るのかしらね。フロントエンドはJavaScript一択でしょうけど。

使ってるDB

06

あれ、SQLServerって上位なん?Oracleってどうしたの?MariaDBには頑張ってほしい。期待上げ。PostgreSQLも上位にあがってるのね。つか、DBランキングとちょっと違う感じがする。↓DBランキング。

07

Oracleって実際どうなんでしょうね。あと、MongoDBはジワジワ来てますな。何系で使われてるんだろ。業務システムって基本RDB使うと思うから、Webサービス的なやつで使ってんのかしら?スキーマレスなDBは業務システム的なデータ構造でガチガチのシステムは微妙な気がするしの。検索のパフォーマンスとかもろもろ。IDで抜くとかだけならMongoの方がパフォーマンスは良さそうなのかしら。いちをNo検証でイメージだけで書いてますので。。。

必要な言語

08

Python大人気すな。AI・機械学習まわりでしょうけども。3年後にはどうなっているかしらね。

使ってるIDE

09

VisualStudioCodeつよ。とゆーか自分もVSCode使ってますね。何か、軽くて使い勝手がよい。ただ、2年前かな?もっと前?に出たばっかで細かいツールというかプラグインが揃いきってないかもかも。でも十分。

所感

やっとJavaは終わったね。.netには頑張ってほしい。C#好き。

で、Pythonがひとまず伸びそうな感じ?今使ってる最中だから人が増えて便利なライブラリとかツールとか増えるとうれしい。まー自分で作れって話ですけど。

意外にもDBはMongoDBが来てるのね。多少は来ると思ってたけど、こんなに来てるとは思ってなかった。Webサービス的なシステムには向いてるのかな。業務システムではちょっと厳しそうな気がする。とりあえずロックが割とゆるかった記憶が。。。

まー、日本で仕事してる身としては、そもそもアンケートに日本からの回答があまり入ってないので世界的にはそんな感じかーという程度。日本てガラパゴスってよく言われるじゃない。世界的な基準のアンケートだと身の回りには割と当てはまらなかったりするしね。

参考サイト

https://insights.stackoverflow.com/survey/2018/

https://db-engines.com/en/ranking_trend

問合せ