react-hot-loader
Webpack config に追加すると、次のエラーが発生します。
Module parse failed: Unexpected character '@' (22:0)
File was processed with these loaders:
* ../../../virgin-land/nice-compile-pc/builder/lib/add-react-hot-loader-to-source.js
* ../../../virgin-land/nice-compile-pc/node_modules/_webpack-string-replacer@0.0.16@webpack-string-replacer/Dist/Loader.js
You may need an additional loader to handle the result of these loaders.
| ]
|
> @observer
| class FilterBar extends React.Component {
| constructor(props) {
const rules = [
{
oneOf: [
// add this one
{
id: 'react-hot-loader',
test: /\.jsx$/,
loader: require.resolve('./add-react-hot-loader-to-source')
},
{
id: 'image',
test: /\.(svg|bmp|gif|png|jpe?g)$/,
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: '[name].[hash:8].[ext]'
}
},
{
id: 'js',
test: /\.(js|jsx|mjs)$/,
loader: require.resolve('babel-loader'),
exclude: /node_modules/,
options: Object.assign({
cacheDirectory: true
}, populateFinalBabelConfig(babelConfig))
},
{
id: 'default',
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: '[name].[hash:8].[ext]'
}
}
]
}
];
ローダーの./add-react-hot-loader-to-source
ソースは次のとおりです。
const PRODUCTION_ENV = 'production';
const EXPORT_DEFAULT_REGEX = /^\s*export\s+default/m;
const EXPORT_DEFAULT_WITH_TRAILING_SPACES_REGEX = /^\s*export\s+default\s+/m;
const DEFAULT_EXPORTED_CLASS_REGEX = /^\s*export\s+default\s+class\s+(.*?)\s+/m;
const DEFAULT_EXPORTED_FUNCTION_REGEX = /^\s*export\s+default\s+function\s+([^(\s]*)\s?\(/m;
const IMPORT_STATEMENT = "import {hot} from 'react-hot-loader/root';\n";
const EXTEND_KEYWORD = 'extends';
/**
* @param {string} source
* @returns {string} A modified source which has the hot reload wrapping
*/
function AddReactHotLoader(source) {
if (process.env.NODE_ENV === PRODUCTION_ENV || !source || !EXPORT_DEFAULT_REGEX.exec(source)) {
return source;
}
let newSource = getImportLine() + source;
const className = getExportDefaultClassName(source);
const functionName = getExportDefaultFunctionName(source);
const defaultExportedName = className || functionName;
console.log('defaultExportedName', defaultExportedName);
return defaultExportedName ? transformSource(newSource, defaultExportedName) : transformSourceDefault(newSource);
}
/**
* @param {string} source
* @param {string} defaultExportedName The name of the origin default export name
* that needs to be wrapped in hot reload
* @returns {string} A source which includes the hot reload wrapper export
*/
function transformSource(source, defaultExportedName) {
source = source.replace(EXPORT_DEFAULT_WITH_TRAILING_SPACES_REGEX, '');
source += `\nexport default hot(module)(${defaultExportedName});`;
console.log('source', source);
return source;
}
/**
* @param {string} source
* @returns {string} A source which includes the hot reload wrapper export
*/
function transformSourceDefault(source) {
source = source.replace(EXPORT_DEFAULT_REGEX, 'const reactAppToMakeSuperHot =');
source += `\nexport default hot(reactAppToMakeSuperHot);`;
console.log('source', source);
return source;
}
/**
* @returns {string} An import statement followed with a line break
*/
function getImportLine() {
return IMPORT_STATEMENT;
}
/**
* Returns the default exported class name if exists or an empty string
* @param {string} source
* @returns {string} A class name which is exported as default
*/
function getExportDefaultClassName(source) {
const matches = source.match(DEFAULT_EXPORTED_CLASS_REGEX);
const hasClassName = matches && matches[1] && matches[1] !== EXTEND_KEYWORD;
return hasClassName ? matches[1] : '';
}
/**
* Returns the default exported function name if exists or an empty string
* @param {string} source
* @return {string} A function name which is exported as default
*/
function getExportDefaultFunctionName(source) {
const matches = source.match(DEFAULT_EXPORTED_FUNCTION_REGEX);
const hasFunctionName = matches && matches[1];
return hasFunctionName ? matches[1] : '';
}
module.exports = AddReactHotLoader;