React と Webpack (3.4.1) を使用して「コンポーネント ライブラリ」を構築しようとしています。アイデアは、 React Cosmosを使用して 1 つの React アプリを作成し、再利用可能なコンポーネントの「ライブラリ」をインタラクティブに構築して探索することです。そのリポジトリには、build
それらのコンポーネントだけを (Github や NPM に) プッシュできるファイルにコンパイルするタスクもあります。また、そのファイル/パッケージを他のプロジェクトにインポートして、再利用可能なコンポーネントにアクセスできます。
注/更新- これを自分で試してみたい方のために、(機能しない) パッケージを NPM: https://www.npmjs.com/package/rs-componentsに公開しました。同じ
yarn add
問題に遭遇する可能性が高いのは、プロジェクトだけです。
この作業の 90% が完了しました。React Cosmos はコンポーネントを正しく表示しており、ビルド タスク ( rimraf dist && webpack --display-error-details --config config/build.config.js
) はエラーなしで実行されています。ただし、リポジトリを Github からパッケージとして別のプロジェクトにプルすると、エラーが発生します。
エラーは、Webpack がコンポーネント ライブラリの依存関係を正しくインポートしていないことが原因のようです。ビルド時にライブラリを縮小/マングルしないと、インポート時に最初に表示されるエラーは次のとおりです。
TypeError: React.Component is not a constructor
実際、デバッガーを投入して調べると、React は空のオブジェクトです。
node_modules
(ごまかして) React をコンパイル済み/ダウンロード済みファイル( ) に直接インポートすることでこれを回避するとconst React = require('../../react/react.js')
、そのエラーは発生しませんが、prop-types
ライブラリのインポートの失敗に関連する同様のエラーが発生します。
TypeError: Cannot read property 'isRequired' of undefined
したがって、私のコードは正しく取り込まれているようですが、コンポーネント ライブラリ ファイルのインポートは正しくバンドルされていないようです。
関連ファイルのほとんどは次のとおりです。
config/build.config.js
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const config = {
entry: path.resolve(__dirname, '../src/index.js'),
devtool: false,
output: {
path: path.resolve(__dirname, '../dist'),
filename: '[name].js'
},
resolve: {
modules: [
path.resolve(__dirname, '../src'),
'node_modules'
],
extensions: ['.js']
},
module: {
rules: []
}
};
// JavaScript
// ------------------------------------
config.module.rules.push({
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
query: {
cacheDirectory: true,
plugins: [
'babel-plugin-transform-class-properties',
'babel-plugin-syntax-dynamic-import',
[
'babel-plugin-transform-runtime',
{
helpers: true,
polyfill: false, // We polyfill needed features in src/normalize.js
regenerator: true
}
],
[
'babel-plugin-transform-object-rest-spread',
{
useBuiltIns: true // We polyfill Object.assign in src/normalize.js
}
]
],
presets: [
'babel-preset-react',
['babel-preset-env', {
targets: {
ie9: true,
uglify: false,
modules: false
}
}]
]
}
}]
});
// Styles
// ------------------------------------
const extractStyles = new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
allChunks: true,
disable: false
});
config.module.rules.push({
test: /\.css$/,
use: 'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]__[hash:base64:5]'
});
config.module.rules.push({
test: /\.(sass|scss)$/,
loader: extractStyles.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
sourceMap: false,
minimize: {
autoprefixer: {
add: true,
remove: true,
browsers: ['last 2 versions']
},
discardComments: {
removeAll: true
},
discardUnused: false,
mergeIdents: false,
reduceIdents: false,
safe: true,
sourcemap: false
}
}
},
{
loader: 'postcss-loader',
options: {
autoprefixer: {
add: true,
remove: true,
browsers: ['last 2 versions']
},
discardComments: {
removeAll: true
},
discardUnused: false,
mergeIdents: false,
reduceIdents: false,
safe: true,
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: false,
includePaths: [
path.resolve(__dirname, '../src/styles')
]
}
}
]
})
});
config.plugins = [extractStyles];
// Images
// ------------------------------------
config.module.rules.push({
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8192
}
});
// Bundle Splitting
// ------------------------------------
const bundles = ['normalize', 'manifest'];
bundles.unshift('vendor');
config.entry.vendor = [
'react',
'react-dom',
'redux',
'react-redux',
'redux-thunk',
'react-router'
];
config.plugins.push(new webpack.optimize.CommonsChunkPlugin({ names: bundles }));
// Production Optimizations
// ------------------------------------
config.plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: false,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: false,
comments: false,
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true
}
})
);
module.exports = config;
コンポーネントの例:
Checkbox.js
import React from 'react';
import { connect } from 'react-redux';
import { map } from 'react-immutable-proptypes';
import classnames from 'classnames';
import { setCheckboxValue } from 'store/actions';
/**
* Renders a Redux-connected Checkbox with label
*
* @param {string} boxID - Unique string identifier of checkbox
* @param {string} name - Label text to display
* @param {function} dispatch - Redux dispatch function
* @param {Immutable.Map} checkboxes - Redux checkboxes Map
* @param {string[]} className - Optional additional classes
*
* @returns {React.Component} A checkbox with globally-tracked value
*/
export function CheckboxUC ({ boxID, name, dispatch, checkboxes, className }) {
const checked = checkboxes.get(boxID);
return (
<label className={ classnames('checkbox rscomp', className) } htmlFor={ boxID }>
<input
className="checkable__input"
type="checkbox"
onChange={ () => {
dispatch(setCheckboxValue(boxID, !checked));
} }
name={ name }
checked={ checked }
/>
<span className="checkable__mark" />
<span className="checkable__label">{ name }</span>
</label>
);
}
const mapStateToProps = state => ({
checkboxes: state.checkboxes
});
const { string, func } = React.PropTypes;
CheckboxUC.propTypes = {
boxID: string.isRequired,
name: string.isRequired,
checkboxes: map.isRequired,
dispatch: func,
className: string
};
export default connect(mapStateToProps)(CheckboxUC);
また、Webpack ビルド タスクの「エントリ」ファイル ( webpack --config config/build.config.js
) は、このパッケージをインポートするアプリケーションがアクセスできるコンポーネントのみをエクスポートすることを目的としています。
src/index.js
import BaseForm from 'components/BaseForm';
import Checkbox from 'components/Checkbox';
import Dropdown from 'components/Dropdown';
import Link from 'components/Link';
import RadioGroup from 'components/RadioGroup';
import { validators } from 'components/BaseForm/utils';
export default {
BaseForm,
Checkbox,
Dropdown,
Link,
RadioGroup,
utils: {
validators
}
};
最後に、不適切に未定義のように見える変数を「インポート」している、コンパイルされた未醜化の JS の行を次に示します。
var React = __webpack_require__(1);
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_prop_types__ = __webpack_require__(3);
これを整理するのに役立つものが他にあれば教えてください。非常に混乱しているので、助けていただければ幸いです。
ありがとう!
編集
多くのものが正しくインポートされているようです。コンパイルされたファイルでデバッガーをスローし、__webpack_require__(n)
さまざまな を試してみると、n
インポートされたさまざまなモジュールが表示されます。残念ながら、React と PropTypes はその中に含まれていないようです。