我正在使用 Webpack、Express、Epilogue、Sequelize、Sqlite3 和 React 构建一个 CRUD Web 应用程序。设置 Webpack 和 Babel 后,我可以将条目添加到数据库中,但不能检索条目。当我添加一个条目时,如果我查看http://localhost:3000/blogposts(我的端点之一),页面是空白的,但是在服务器输出中我看到我的条目被添加了。
要从我使用的数据库中检索条目:
getPosts = async () => {
const response = await fetch('/blogposts');
const data = await response.json();
data.forEach(item => item.editMode = false);
this.setState({ data })
}
我得到错误: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 1
我认为这是 babel/webpack 和 await/async 的错误。
我的 webpack.config.js:
const path = require("path")
const HtmlWebPackPlugin = require("html-webpack-plugin")
module.exports = {
entry: {
main: './src/index.js'
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'web',
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
},
]
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./src/index.html",
excludeChunks: [ 'server' ]
})
],
resolve: {
extensions: ["*",".js", ".jsx", "json"],
alias: {
'components': path.resolve(__dirname, '/components')
}
},
}
我的 webpackserver.config.js:
const path = require('path')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: {
server: './src/server/server.js',
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
resolve: {
extensions: ['.js', '.jsx'],
alias: {
'components': path.resolve(__dirname, '/components')
}
},
node: {
__dirname: false,
__filename: false,
},
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
}
我的 server.js:
import path from 'path'
import express from 'express'
require('dotenv').config();
const cors = require('cors');
const bodyParser = require('body-parser');
const session = require('express-session');
const { ExpressOIDC } = require('@okta/oidc-middleware');
const Sequelize = require('sequelize');
const epilogue = require('epilogue'), ForbiddenError = epilogue.Errors.ForbiddenError;
const port = process.env.PORT || 3000
const app = express(),
DIST_DIR = __dirname,
HTML_FILE = path.join(DIST_DIR, '/src/index.html')
app.use(express.static(DIST_DIR))
app.get('*', (req, res) => {
res.sendFile(HTML_FILE)
})
// session support is required to use ExpressOIDC
app.use(session({
secret: process.env.RANDOM_SECRET_WORD,
resave: true,
saveUninitialized: false
}));
const oidc = new ExpressOIDC({
issuer: `${process.env.OKTA_ORG_URL}/oauth2/default`,
client_id: process.env.OKTA_CLIENT_ID,
client_secret: process.env.OKTA_CLIENT_SECRET,
redirect_uri: process.env.REDIRECT_URL,
scope: 'openid profile',
routes: {
callback: {
path: '/authorization-code/callback',
defaultRedirect: '/admin'
}
}
});
// ExpressOIDC will attach handlers for the /login and /authorization-code/callback routes
app.use(oidc.router);
app.use(cors());
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'src')));
app.get('/home', (req, res) => {
res.sendFile(path.join(__dirname, './home.html'));
});
app.get('/admin', oidc.ensureAuthenticated(), (req, res) => {
res.sendFile(path.join(__dirname, './admin.html'));
});
app.get('/logout', (req, res) => {
req.logout();
res.redirect('/home');
});
console.log("redirect");
app.get('/', (req, res) => {
res.redirect('/home');
});
// //for each blog post
app.get('/lifestyle/:title', function (req, res) {
res.send('Blogpost template here!')
})
const database = new Sequelize({
dialect: 'sqlite',
storage: './db.sqlite',
operatorsAliases: false,
});
const Post = database.define('posts', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
});
const blogPost = database.define('blogposts', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
published: {
type: Sequelize.BOOLEAN,
allowNull: false,
defaultValue: false,
},
});
const test = database.define('test', {
title: Sequelize.STRING,
content: Sequelize.TEXT,
});
epilogue.initialize({ app, sequelize: database });
const PostResource = epilogue.resource({
model: Post,
endpoints: ['/posts', '/posts/:id'],
});
const blogPostResource = epilogue.resource({
model: blogPost,
endpoints: ['/blogposts', '/blogposts/:id'],
});
PostResource.all.auth(function (req, res, context) {
return new Promise(function (resolve, reject) {
resolve(context.continue);
})
});
database.sync().then(() => {
oidc.on('ready', () => {
app.listen(port, () => console.log(`My Blog App listening on port ${port}!`))
});
});
oidc.on('error', err => {
// An error occurred while setting up OIDC
console.log("oidc error: ", err);
});
我的 package.json:
{
"name": "blog",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"build": "rm -rf dist && webpack --mode development --config webpackserver.config.js && webpack --mode development",
"start": "node ./dist/server.js"
},
"proxy": "http://localhost:3000",
"author": "",
"license": "ISC",
"dependencies": {
"@okta/oidc-middleware": "1.0.2",
"D": "1.0.0",
"babel-polyfill": "6.26.0",
"babel-preset-es2015": "6.24.1",
"babel-preset-stage-0": "6.24.1",
"babel-runtime": "6.26.0",
"body-parser": "1.18.3",
"cors": "2.8.5",
"dotenv": "6.2.0",
"epilogue": "0.7.1",
"express": "4.16.4",
"express-session": "1.15.6",
"fibers": "4.0.2",
"node-sass": "4.13.0",
"rc": "1.2.8",
"sass": "1.23.7",
"sequelize": "4.44.3",
"sqlite3": "4.1.0",
"webpack-isomorphic-tools": "3.0.6"
},
"devDependencies": {
"@babel/core": "7.7.5",
"@babel/plugin-proposal-class-properties": "7.7.4",
"@babel/plugin-transform-runtime": "7.7.6",
"@babel/preset-env": "7.7.6",
"@babel/preset-react": "7.7.4",
"@material-ui/core": "4.7.2",
"@material-ui/icons": "4.5.1",
"babel-loader": "8.0.6",
"babel-plugin-transform-runtime": "6.23.0",
"babel-preset-env": "1.7.0",
"css-loader": "3.3.2",
"file-loader": "5.0.2",
"grommet": "2.9.0",
"html-loader": "0.5.5",
"html-webpack-plugin": "3.2.0",
"json-loader": "0.5.7",
"nodemon": "1.18.9",
"nodemon-webpack-plugin": "4.2.2",
"react": "16.12.0",
"react-dom": "16.12.0",
"react-router-dom": "5.1.2",
"sass-loader": "8.0.0",
"style-loader": "1.0.1",
"styled-components": "4.4.1",
"typeface-roboto": "0.0.75",
"webpack": "4.41.2",
"webpack-cli": "3.3.10",
"webpack-node-externals": "1.7.2"
}
}
我的 .babelrc"
{
"presets": [
"@babel/preset-env",
"@babel/react"
],
"plugins" : [
"@babel/plugin-proposal-class-properties",
"@babel/plugin-transform-runtime"
]
}