--- title: Riot+ElectronでMarkdownエディタを作る tags: riot Electron author: elastic slide: false --- riotが最近自分の中でキてるのでなんか作りたいなと思って、markdownエディタを作ってみました。 riot中心なのでelectronの説明はしません(そもそも起動でしか使ってない) ## 自分の環境 - Windows 10 home - node.js v8.9.1 - npm 5.5.1 ## どうやる - markdown-it >> markdownパーサ - highlight.js >> コードをハイライト表示してくれる - ace >> web上に埋め込めるエディター リアルタイムにプレビューさせたいので, aceエディタの中身が変更されたら、エディタの値をmarkdown-itでパースして表示させます。そして表示されたやつにコードがあったらhighlight.jsでハイライトを付けます。 その他ファイル読み込みと上書き保存機能も付けます やっていきましょう ## ディレクトリ構成 ``` -public -index.html -main.js -src -app -editor -editor.tag -editor.css -header -header.tag -header.css -preview -preview.tag -preview.css -app.tag -app.css -main.js ``` ## パッケージと設定ファイル ```package.json { "name": "app", "version": "1.0.0", "description": "", "main": "main.js", "keywords": [], "author": "", "license": "ISC", "dependencies": { "electron": "^1.7.9" }, "devDependencies": { "babel-core": "^6.26.0", "babel-loader": "^7.1.2", "babel-preset-es2015-riot": "^1.1.0", "bootstrap": "^3.3.7", "brace": "^0.11.0", "css-loader": "^0.28.7", "github-markdown-css": "^2.9.0", "highlight.js": "^9.12.0", "jquery": "^3.2.1", "markdown-it": "^8.4.0", "riot": "^3.7.4", "riot-tag-loader": "^1.0.0", "style-loader": "^0.19.0", "webpack": "^3.10.0" }, "scripts": { "start": "electron ./public/main.js", "watch": "webpack --watch --progress --color", "build": "webpack --progress --color" } } ``` ```webpack.config.js const path = require('path') const webpack = require('webpack') module.exports = { entry: './src/main.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'public/javascripts'), }, module: { rules: [{ enforce: 'pre', test: /\.tag$/, exclude: /node_modules/, loader: 'riot-tag-loader', query: { type: 'es6', debug: true } }, { test: /\.css/, loaders: [ 'style-loader', { loader: 'css-loader', options: { url: false } } ] }, { test: /\.(tag|js)$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: ['es2015-riot'], }, }, ], }, devtool: 'source-map', resolve: { extensions: ['*', '.js'], }, plugins: [ new webpack.optimize.UglifyJsPlugin({ sourceMap: true, }), new webpack.optimize.ModuleConcatenationPlugin(), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.AggressiveMergingPlugin(), new webpack.ProvidePlugin({ riot: 'riot', jQuery: 'jquery', $: 'jquery' }), ] } ``` ## コード まずはhtmlと起動スクリプトを書きます。 ```index.html Markdown Editor ``` ```public/main.js // Electron起動スクリプト。 const { app, BrowserWindow } = require('electron') const path = require('path') const url = require('url') let mainWindow function createWindow() { mainWindow = new BrowserWindow({ width: 1200, height: 1000 }) mainWindow.loadURL(url.format({ pathname: path.join(__dirname, 'index.html'), protocol: 'file:', slashes: true })) mainWindow.on('closed', () => { mainWindow = null }) } app.on('ready', createWindow) app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit() } }) app.on('activate', () => { if (win === null) { createWindow() } }) ``` `npm start`で動作確認 アプリが立ち上がれば大丈夫です:smile: ## riot側のコード コンポーネント指向なので - ヘッダーコンポーネント (app-header) - エディタコンポーネント (app-editor) - プレビューコンポーネント (app-preview) の三つのコンポーネントに分けます。 後は、ヘッダー用とエディター用のオブザーブルを作って、コンポーネント間の値渡しやイベント検知などもしやすくします。 ```src/main.js //bootstrapとmarkdownのcss等。デザイン部分なのであまり重要ではない import '../node_modules/bootstrap/dist/css/bootstrap.min.css' import '../node_modules/github-markdown-css/github-markdown.css' import '../node_modules/highlight.js/styles/github.css' import '../node_modules/bootstrap' //app-rootタグを読み込む import './app/app.css' import './app/app.tag' riot.mount('app-root') ``` **app.tag** ```html
``` **header.tag** ```html
``` **editor.tag** ```html
``` **preview.tag** ```html
``` ## cssコード 適当です。 ```app.css .container-fluid { padding: 0px; width: 100%; height: 100%; } .col-sm-6 { padding: 0px; } ``` ```preview.css app-preview article { padding: 5px; margin: 10px; height: 100%; overflow: auto; } ``` ```header.css app-header #file { display: none; } ``` ```editor.css app-editor #editor { position: relative; height: 100%; } ``` ## 動作確認 `npm run build`してから`npm start`を実行してください。 結果 ![image.png](https://qiita-image-store.s3.amazonaws.com/0/206222/647cbf58-78fa-3e09-2f39-eb1ee162f657.png) :+1::+1::+1::+1::+1::+1::+1::+1::+1::+1::+1: ## 最後に * riotのobservable機能がとても便利だということが分かった。 * webpackでなぜかfsがうまく使えなかったし、electronをimportしようとするとエラーが出ちゃう。。。