この記事では、使用できるユニバーサルJavaScriptコンポーネントの作成方法について説明します
- 反応成分として;
- preactコンポーネントとして;
- 角度コンポーネントとして;
- Webコンポーネントとして
- DOMElementでレンダリングするためのjQuery関数として。
- DOMElementでレンダリングするためのネイティブ関数として。
なぜ誰がそれを必要とするのか
JavaScript開発の世界は非常に細分化されています。 人気のあるフレームワークは多数あり、そのほとんどは互いに完全に互換性がありません。 そのような状況では、特定のフレームワークを選択するJavaScriptコンポーネントおよびライブラリの開発者は、このフレームワークが使用しない非常に多くの対象者を自動的に拒否します。 これは深刻な問題であり、その解決策は記事で提案されています。
すべての実装方法
- Reactコンポーネントを書きましょう。
- Reactと同様に連携して動作するpreactおよびpreact-compat JavaScriptライブラリを使用し、サイズが20キロバイトの哀れな重量で、他のすべてのラッパーを作成します。
- Webpackを使用してアセンブリを構成します。
コンポーネントコードを書く
たとえば、このタイプのドーナツチャートを作成します。
ここでは驚くべきことは何も表示されません-コードだけです。
import React from 'react'; export default class DonutChart extends React.Component { render() { const { radius, holeSize, text, value, total, backgroundColor, valueColor } = this.props; const r = radius * (1 - (1 - holeSize)/2); const width = radius * (1 - holeSize); const circumference = 2 * Math.PI * r; const strokeDasharray = ((value * circumference) / total) + ' ' + circumference; const transform = 'rotate(-90 ' + radius + ',' + radius + ')'; const fontSize = r * holeSize * 0.6; return ( <div style = {{ textAlign: 'center', fontFamily: 'sans-serif' }}> <svg width = {radius * 2 + 'px'} height = {radius * 2 + 'px'}> <circle r = {r + 'px'} cx = {radius + 'px'} cy = {radius + 'px'} transform = {transform} fill = 'none' stroke = {backgroundColor} strokeWidth = {width} /> <circle r = {r + 'px'} cx = {radius + 'px'} cy = {radius + 'px'} transform = {transform} fill = 'none' stroke = {valueColor} strokeWidth = {width} strokeDasharray = {strokeDasharray} /> <text x = {radius + 'px'} y = {radius + 'px' }dy = {fontSize/3 + 'px'} textAnchor = 'middle' fill = {valueColor} fontSize = {fontSize + 'px'} > {~~(value * 1000 / total) / 10}% </text> </svg> <div style = {{ marginTop: '10px' }}> {text} </div> </div> ); } } DonutChart.defaultProps = { holeSize : 0.8, radius : 65, backgroundColor : '#d1d8e7', valueColor : '#49649f' };
結果はどうあるべきか
Webpackアセンブリを構成する
基本的なWebpack構成
var webpack = require('webpack'); module.exports = { output: { path: './dist' }, resolve: { extensions: ['', '.js'], }, module: { loaders: [ { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: [ 'latest', 'stage-0', 'react' ], plugins: [ 'transform-react-remove-prop-types', 'transform-react-constant-elements' ] } } ] }, plugins: [ new webpack.DefinePlugin({ 'process.env.NODE_ENV': "'production'" }), new webpack.optimize.DedupePlugin(), new webpack.optimize.OccurrenceOrderPlugin(), new webpack.optimize.AggressiveMergingPlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false }, comments: false, sourceMap: true, mangle: true, minimize: true }) ] };
package.jsonにスクリプトを追加してプロジェクトをビルドします
"scripts": { "build:preact": "node ./scripts/build-as-preact-component.js", "build:react": "node ./scripts/build-as-react-component.js", "build:webcomponent": "node ./scripts/build-as-web-component.js", "build:vanila": "node ./scripts/build-as-vanila-component.js", "build:jquery": "node ./scripts/build-as-jquery-component", "build:angular": "node ./scripts/build-as-angular-component", "build": "npm run build:preact && npm run build:react && npm run build:webcomponent && npm run build:vanila && npm run build:jquery && npm run build:angular" }
WebコンポーネントのWebpackアセンブリとラッパー
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); config.resolve.alias = { 'react': 'preact-compat', 'react-dom': 'preact-compat' }; config.entry = './src/DonutChartWebComponent.js'; config.output.filename = 'DonutChartWebComponent.js'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
ラッパー
import React from 'react'; import ReactDOM from 'react-dom'; import DonutChart from './DonutChart'; const proto = Object.create(HTMLElement.prototype, { attachedCallback: { value: function() { const mountPoint = document.createElement('span'); this.createShadowRoot().appendChild(mountPoint); const props = { radius : +this.getAttribute('radius') || undefined, holeSize : +this.getAttribute('hole-size') || undefined, text : this.getAttribute('text') || undefined, value : +this.getAttribute('value') || undefined, total : +this.getAttribute('total') || undefined, backgroundColor : this.getAttribute('background-color') || undefined, valueColor : this.getAttribute('value-color') || undefined }; ReactDOM.render(( <DonutChart {...props}/> ), mountPoint); } } }); document.registerElement('donut-chart', {prototype: proto});
使用例
<donut-chart value="39.6" total="100" text="Hello Web Components"></donut-chart>
結果
WebpackビルドとAngularのラッパー
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); config.resolve.alias = { 'react': 'preact-compat', 'react-dom': 'preact-compat' }; config.entry = './src/DonutChartAngularComponent.js'; config.output.filename = 'DonutChartAngularComponent.js'; config.output.library = 'DonutChart'; config.output.libraryTarget = 'umd'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
ラッパー
import React from 'react'; import ReactDOM from 'react-dom'; import DonutChart from './DonutChart'; const module = angular.module('future-charts-example', []); module.directive('donutChart', function() { return { restrict: 'E', link: function(scope, element, attrs) { const props = { radius : +attrs['radius'] || undefined, holeSize : +attrs['hole-size'] || undefined, text : attrs['text'] || undefined, value : +attrs['value'] || undefined, total : +attrs['total'] || undefined, backgroundColor : attrs['background-color'] || undefined, valueColor : attrs['value-color'] || undefined }; ReactDOM.render(( <DonutChart {...props}/> ), element[0]); } }; });
使用例
<body ng-app="future-charts-example"> <donut-chart value="89.6" total="100" text="Hello Angular"></donut-chart> </body>
結果
jQueryのWebpackビルドとラッパー
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); config.resolve.alias = { 'react': 'preact-compat', 'react-dom': 'preact-compat' }; config.entry = './src/DonutChartJQueryComponent.js'; config.output.filename = 'DonutChartJQueryComponent.js'; config.output.library = 'DonutChart'; config.output.libraryTarget = 'umd'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
ラッパー
import React from 'react'; import ReactDOM from 'react-dom'; import DonutChart from './DonutChart'; jQuery.fn.extend({ DonutChart: function(props) { this.each( function () { ReactDOM.render(( <DonutChart {...props}/> ), this); } ); } });
使用例
$('#app').DonutChart({ value : 42.1, total : 100, text : 'Hello jQuery' });
結果
VanilaJSのWebpackアセンブリおよびラッパー(ネイティブ関数から使用)
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); config.resolve.alias = { 'react': 'preact-compat', 'react-dom': 'preact-compat' }; config.entry = './src/DonutChartVanilaComponent.js'; config.output.filename = 'DonutChartVanilaComponent.js'; config.output.library = 'DonutChart'; config.output.libraryTarget = 'umd'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
ラッパー
import React from 'react'; import ReactDOM from 'react-dom'; import DonutChart from './DonutChart'; module.exports = function DonutChartVanilaComponent(mountPoint, props) { ReactDOM.render(( <DonutChart {...props}/> ), mountPoint); };
使用例
DonutChart(document.getElementById('app'), { value : 57.4, total : 100, text : 'Hello Vanila' });
結果
React用のWebpackビルド
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); var react = { root: 'React', commonjs2: 'react', commonjs: 'react' }; var reactDom = { root: 'ReactDOM', commonjs2: 'react-dom', commonjs: 'react-dom' }; config.externals = { 'react': react, 'react-dom': reactDom }; config.entry = './src/DonutChartUMD.js'; config.output.filename = 'DonutChartReact.js'; config.output.library = 'DonutChart'; config.output.libraryTarget = 'umd'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
結果
Preact用のWebpackビルド
基本的なWebpack構成およびビルドの変更
var webpack = require('webpack'); var config = require('./webpack.config'); var statsConfig = require('./statsConfig'); var preactCompat = { root: 'preactCompat', commonjs2: 'preact-compat', commonjs: 'preact-compat' }; config.externals = { 'react': preactCompat, 'react-dom': preactCompat }; config.entry = './src/DonutChartUMD.js'; config.output.filename = 'DonutChartPreact.js'; config.output.library = 'DonutChart'; config.output.libraryTarget = 'umd'; webpack(config).run(function (err, stats) { console.log(stats.toString(statsConfig)); });
結果
おわりに
各オプションの重量はどれくらいになりますか:
反応する | プリアクト | バニラス | jQuery | 角度 | Webコンポーネント |
---|---|---|---|---|---|
コンポーネントコード(3kb) | コンポーネントコード(3kb) | コンポーネントコード(3kb) | コンポーネントコード(3kb) | コンポーネントコード(3kb) | コンポーネントコード(3kb) |
ラップ(1kb) | ラップ(1kb) | ラップ(1kb) | ラップ(1kb) | ||
preact.min.js(3kb) | preact.min.js(3kb) | preact.min.js(3kb) | preact.min.js(3kb) | ||
preact-compat.min.js(18kb) | preact-compat.min.js(18kb) | preact-compat.min.js(18kb) | preact-compat.min.js(18kb) | ||
3kb | 3kb | 25kb | 25kb | 25kb | 25kb |
他のフレームワークで、またはWebコンポーネントとしてReactコンポーネントを使用するための20キロバイトのオーバーヘッドは、優れた結果です。 何らかの種類のReactコンポーネントを開発している場合は、知っている-誰でも利用できるようにすることができる-それは非常に簡単です。 このチュートリアルが世界を少し良くし、JavaScript開発ユニバースのひどい断片化を減らすのに役立つことを願っています。