Итак, я создаю веб-приложение, мы назовем WebApp
, который является модулем React, который использует компоненты из пользовательского модуля React, мы назовем CustomModule
, который также находится на моем локальном компьютере. , Я пытался импортировать определенные компоненты из CustomModule
в WebApp
и столкнулся со следующей ошибкой, которая появляется при запуске webpack-dev-server -d
в WebApp
:
ERROR in /CustomModule/Components/LoadingSpinner/LoadingSpinner.jsx
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: /CustomModule/Components/LoadingSpinner/LoadingSpinner.jsx: Unexpected token, expected ";" (11:17)
9 |
10 | export const Spinner = () => {
> 11 | var imgStyle : object = {
| ^
12 | height:"75%",
13 | padding:"2px 0 0 2px"
14 | } ;
at Parser.raise (/WebApp/node_modules/@babel/parser/lib/index.js:3851:17)
at Parser.unexpected (/WebApp/node_modules/@babel/parser/lib/index.js:5167:16)
at Parser.semicolon (/WebApp/node_modules/@babel/parser/lib/index.js:5149:40)
at Parser.parseVarStatement (/WebApp/node_modules/@babel/parser/lib/index.js:7763:10)
at Parser.parseStatementContent (/WebApp/node_modules/@babel/parser/lib/index.js:7358:21)
at Parser.parseStatement (/WebApp/node_modules/@babel/parser/lib/index.js:7291:17)
at Parser.parseBlockOrModuleBlockBody (/WebApp/node_modules/@babel/parser/lib/index.js:7868:25)
at Parser.parseBlockBody (/WebApp/node_modules/@babel/parser/lib/index.js:7855:10)
at Parser.parseBlock (/WebApp/node_modules/@babel/parser/lib/index.js:7839:10)
at Parser.parseFunctionBody (/WebApp/node_modules/@babel/parser/lib/index.js:6909:24)
@ /CustomModule/Components/LoadingSpinner/index.js 1:0-65 1:0-65
@ /CustomModule/Components/index.js
@ ./ClientScripts/DataExplorer/Dashboard/containers/DashboardContent.jsx
@ ./ClientScripts/DataExplorer/Dashboard/index.js
@ ./ClientScripts/Route/RouteConfig.jsx
@ ./ClientScripts/Route/index.js
@ ./ClientScripts/Main.jsx
@ ./ClientScripts/index.js
@ multi (webpack)-dev-server/client?http://localhost:9000 ./ClientScripts/index.js
Оба модуля используют Flow
, babel
и webpack
. Я настроил файлы package.json
, webpack.config.js
, .flowconfig
и .babelrc
соответственно в каждом модуле. Затем я символически связал CustomModule
с WebApp
, используя npm link
. Я строю CustomModule
, используя webpack
, затем пытаюсь построить WebApp
, который содержит оператор импорта для использования компонента из CustomModule
.
Версия
node: v9.0.0
npm: 5.5.1
@babel/cli: 7.2.3
@babel/core: 7.4.3
@babel/preset-flow: 7.0.0
babel-loader: 8.0.5
flow: 0.2.3
flow-webpack-plugin: 1.2.0
webpack: 4.16.5
WebApp webpack.config.js
const webpack = require('webpack');
const path = require('path');
const glob = require('glob');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const FlowWebpackPlugin = require('flow-webpack-plugin');
module.exports = {
entry: {
vendor: ['babel-polyfill', 'react', 'react-dom'],
annotationService: glob.sync('./ClientScripts/AnnotationService/*.js'),
repositoryService: glob.sync('./ClientScripts/RepositoryService/*.js'),
timelineService: glob.sync('./ClientScripts/TimelineService/*.js'),
filterService: glob.sync('./ClientScripts/DataExplorer/Dashboard/FilterServices/*.js'),
platform: './ClientScripts/index.js',
objects: glob.sync("./ClientScripts/RepositoryService/Objects/*.js"),
sass: './sass/main.scss'
},
output: {
path: path.join(__dirname, 'reactDist'),
filename: 'js/[name].js',
sourceMapFilename: 'map/[name].map'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
resolve: {
alias: {
Interfaces: path.resolve(__dirname, 'ClientScripts/Interfaces/'),
Layout: path.resolve(__dirname, 'ClientScripts/Layout/'),
Navigation: path.resolve(__dirname, 'ClientScripts/Navigation/'),
Redux: path.resolve(__dirname, 'ClientScripts/Redux/'),
RepositoryService: path.resolve(__dirname, 'ClientScripts/RepositoryService/'),
TimelineService: path.resolve(__dirname, 'ClientScripts/TimelineService/'),
FilterService: path.resolve(__dirname, 'ClientScripts/DataExplorer/Dashboard/FilterServices/'),
AnnotationService: path.resolve(__dirname, 'ClientScripts/AnnotationService/'),
Route: path.resolve(__dirname, 'ClientScripts/Route/'),
Timeline: path.resolve(__dirname, 'ClientScripts/Timeline/'),
TimelineEditor: path.resolve(__dirname, 'ClientScripts/TimelineEditor/'),
Utilities: path.resolve(__dirname, 'ClientScripts/jsutils/'),
ReactUtils: path.resolve(__dirname, 'ClientScripts/reactUtils/'),
Images: path.resolve(__dirname, 'img/'),
},
symlinks: true
},
target: 'web',
node: {
fs: "empty"
},
externals: {
'winston': 'require("winston")
},
module: {
rules: [
{ test: /\.js$/, loader: 'babel-loader' },
{ test: /\.jsx$/, loader: 'babel-loader' },
{ test: /\.env$/, loader: "file-loader?name=index.[ext]", exclude: [/node_modules/] },
{
test: /\.scss$|\.css$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
use: [{
loader: "css-loader",
options: {
minimize: true
}
},'sass-loader']
})
},
{ test: /\.(jpe?g|png|gif|svg)$/,
loader: 'file-loader?name=img/[name].[ext]?',
options: {
name (file) {
if (process.env.environment === 'prod') {
return '[path][name].[hash].[ext]'
}
return '[path][name].[ext]'
}
}
}
]
},
plugins: [
new ExtractTextPlugin({ filename: 'css/timeline.[md5:contenthash:hex:20].css', disable: false, allChunks: true }),
new FlowWebpackPlugin()
]
}
WebApp .flowconfig
[ignore]
.*/node_modules/flow-webpack-plugin/.*
.*/node_modules/.*\.json$
.*/node_modules/\.staging/.*
[libs]
flow-typed
[options]
module.name_mapper='^Interfaces\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Interfaces/\1'
module.name_mapper='^Layout\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Layout/\1'
module.name_mapper='^Navigation\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Navigation/\1'
module.name_mapper='^Redux\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Redux/\1'
module.name_mapper='^RepositoryService\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/RepositoryService/\1'
module.name_mapper='^Route\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Route/\1'
module.name_mapper='^Timeline\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/Timeline/\1'
module.name_mapper='^TimelineEditor\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/TimelineEditor/\1'
module.name_mapper='^Utilities\/\(.*\)$' -> '<PROJECT_ROOT>/ClientScripts/jsutils/\1'
module.name_mapper='^Images\/\(.*\)$' -> '<PROJECT_ROOT>/img/\1'
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.svg
module.file_ext=.json
CustomModule webpack.config.js
const webpack = require('webpack');
const path = require('path');
const glob = require('glob');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const FlowWebpackPlugin = require('flow-webpack-plugin');
module.exports = {
entry: {
vendor: ['babel-polyfill', 'react', 'react-dom'],
components: './Components/index.js',
sass: './sass/main.scss'
},
output: {
path: path.join(__dirname, 'reactDist'),
filename: 'js/[name].js',
sourceMapFilename: 'map/[name].map'
},
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
resolve: {
alias: {
Components: path.resolve(__dirname, 'Components/'),
Images: path.resolve(__dirname, 'img/'),
Utilities: path.resolve(__dirname, 'Utilities/')
},
// extensions: ['', '.js', '.jsx']
},
target: 'web',
node: {
fs: "empty"
},
externals: {
'winston': 'require("winston")'
},
module: {
rules: [
{ test: /\.js$/, loader: 'babel-loader', exclude: [/node_modules/] },
{
test: /\.jsx$/,
loader: 'babel-loader',
exclude: [/node_modules/],
query: {
presets: ['@babel/preset-flow']
}
},
{ test: /\.env$/, loader: "file-loader?name=index.[ext]", exclude: [/node_modules/] },
{
test: /\.scss$|\.css$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract({
use: [{
loader: "css-loader",
options: {
minimize: true
}
},'sass-loader']
})
},
{
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'file-loader?name=img/[name].[ext]?',
options: {
name (file) {
if (process.env.environment === 'prod') {
return '[path][name].[hash].[ext]'
}
return '[path][name].[ext]'
}
}
}
]
},
plugins: [
new ExtractTextPlugin({ filename: 'css/timeline.[md5:contenthash:hex:20].css', disable: false, allChunks: true }),
new FlowWebpackPlugin(),
]
}
CustomModule .flowconfig
[ignore]
.*/node_modules/flow-webpack-plugin/.*
.*/node_modules/.*\.json$
.*/node_modules/\.staging/.*
[libs]
flow-typed
[options]
module.name_mapper='^Components\/\(.*\)$' -> '<PROJECT_ROOT>/Components/\1'
module.name_mapper='^Images\/\(.*\)$' -> '<PROJECT_ROOT>/img/\1'
module.name_mapper='^Utilities\/\(.*\)$' -> '<PROJECT_ROOT>/Utilities/\1'
module.file_ext=.js
module.file_ext=.jsx
module.file_ext=.svg
module.file_ext=.json
Один и тот же файл .babelrc используется для обоих модулей
/*
./.babelrc
*/
{
"presets":[
"@babel/preset-env", "@babel/preset-react", "@babel/preset-flow"
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-syntax-import-meta",
"@babel/plugin-transform-flow-strip-types",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-json-strings",
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
],
"@babel/plugin-proposal-function-sent",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-throw-expressions"
]
}
Я ожидаю, что результат webpack-dev-server
не даст никаких ошибок вместо Module build failed
ошибки, которая выдается выше при разборе babel.