So I'm creating a web app, we'll call WebApp
, which is a React module that uses components from a custom React module, we'll call CustomModule
, that is also located on my local machine. I've been trying to import certain components from CustomModule
in WebApp
and have been running into the following error that appears when running webpack-dev-server -d
in 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
Both modules use Flow
, babel
, and webpack
. I've set up the package.json
, webpack.config.js
, .flowconfig
, and .babelrc
files accordingly in each module. Then I symbolically linked CustomModule
to WebApp
using npm link
. I build the CustomModule
using webpack
then attempt to build the WebApp
which contains an import statement to use a component from CustomModule
.
Versions
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
The same .babelrc is used for both modules
/*
./.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"
]
}
I expect the result of the webpack-dev-server
to yield no errors instead of the Module build failed
error that is thrown above during babel parsing.