Refused to apply style from 'http://localhost:3001/css/style.css'
because its MIME type ('text/html') is not a supported stylesheet MIME
type, and strict MIME checking is enabled.
I know this has been discussed here 'style sheet not loading because of MIME type' but I cannot solve my issue using the tips provided.
I am honestly quite lost as to what to do... did anyone have any other suggests that were previously not mentioned in the other post?
client directoy
layouts
default.hbs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://fonts.googleapis.com/css?family=Nunito+Sans:400,600,700" rel="stylesheet">
<link rel="stylesheet" href="/css/style.css">
<!--<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">-->
<title>Spoty</title>
<title>{{title}}</title>
</head>
<body>
{{{body}}}
</body>
</html>
root directory
index.js
'use strict';
const server = require('./server')();
const config = require('./config');
server.create(config);
server.start();
server directory
index.js
'use strict';
const express = require('express');
const bodyParser = require('body-parser');
const expressHandlebars = require('express-handlebars');
module.exports = () => {
let server = express();
let create;
let start;
// creates server
create = (config) => {
let routes = require('./routes');
// server settings
server.set('env', config.env);
server.set('port', config.port);
server.set('hostname', config.hostname);
server.set('viewDir', config.viewDir);
// middleware for parsing json
server.use(bodyParser.json());
// Setup view engine
server.engine('.hbs', expressHandlebars({
defaultLayout: 'default',
layoutsDir: config.viewDir + '/layouts',
extname: '.hbs'
}));
server.set('views', server.get('viewDir'));
server.set('view engine', '.hbs');
server.use(express.static(__dirname + '/client'));
// Set up routes
routes.init(server);
};
// start server
start = () => {
let hostname = server.get('hostname');
let port = server.get('port');
server.listen(port, () => {
console.log('Express server listening on - http://' + hostname + ':' + port);
});
};
return {
create, start
}
};
server/routes
index.js
const homeRoute = require('./home');
function init(server) {
server.get('/', function (req, res) {
console.log('error here');
res.redirect('/home');
});
server.use('/home',homeRoute);
}
module.exports = {
init
};
home.js
const express = require('express');
const homeController = require('../controllers/home');
let router = express.Router();
router.get('/',homeController.index);
module.exports = router;
server/controllers
home.js
function index(req, res) {
res.render('home/index', {
title: 'Home Page'
});
}
module.exports = {
index
};
package.json
{
"name": "example",
"version": "0.0.0",
"private": true,
"scripts": {
"watch:sass": "node-sass /client/sass/main.scss /client/css/style.css -w",
"devserver": "live-server",
"start": " node index.js npm-run-all --parallel devserver watch:sass",
"compile:sass": "node-sass sass/main.scss css/style.comp.css",
"build:css": "npm-run-all compile:sass"
},
"dependencies": {
"body-parser": "^1.18.3",
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.16.0",
"express-handlebars": "^3.0.0",
"hbs": "^4.0.1",
"http-errors": "~1.6.2",
"jade": "~1.11.0",
"lodash": "^4.17.10",
"morgan": "~1.9.0"
},
"devDependencies": {
"nodemon": "^1.18.3",
"autoprefixer": "^8.6.4",
"concat": "^1.0.3",
"node-sass": "^4.9.0",
"npm-run-all": "^4.1.3",
"postcss-cli": "^5.0.1"
}
}
config
index.js
const _ = require('lodash');
const env = process.env.NODE_ENV || 'local';
const envConfig = require(`./${env}`);
const defaultCofig = env;
module.exports = _.merge(defaultCofig, envConfig);
local.js
let localConfig = {
hostname: 'localhost',
port: 3001,
viewDir: './client/views'
};
module.exports = localConfig;
git repo: https://github.com/rostgoat/NodeExpress
Related
I'm trying to send an email using nodemailer with a template using handlebars, however, I can't get the template to show on the email. In network, the api that sends the email is showing the correct preview and response (in html) for what should be included in the template, but this information is not being displayed in the sent email. This is my first time doing this, and I have been trying to follow all the steps in examples/ tutorials on how to do this, but nothing seems to be working. I would really appreciate any help or advice on how to get my emails to send with the template. Thank you!
Note: orders.hbs is my handlebars document and is within the views folder
mailer.js
import express from 'express';
import expressAsyncHandler from 'express-async-handler';
import nodemailer from 'nodemailer';
import hbs from 'nodemailer-express-handlebars';
import handlebars from 'handlebars';
import Order from './models/orderModel.js';
import path from 'path';
import fs from 'fs';
const mailerRouter = express.Router();
/*
mailerRouter.engine('handlebar', exphbs());
mailerRouter.set('view engine', 'handlebars');
*/
mailerRouter.post (
'/order',
expressAsyncHandler(async (req, res) => {
const email = req.body.email
const orderId = req.body.orderId
const em = req.body.em;
const sender = req.body.sender;
const orderNum = req.body.orderNum
const emailBody = await Order.findById(orderId).lean()
if (emailBody) {
res.render('orders', {data: emailBody})
}
const sub = `Order: ${orderId}`
let transporter = nodemailer.createTransport({
host: 'smtp.gmail.com',
service: 'gmail',
auth: {
type: 'OAuth2',
user: sender,
pass: '',
clientId: '',
clientSecret: '',
refreshToken: '',
}
})
/*
transporter.use('compile', hbs({
viewEngine: 'express-handlebars',
viewPath:'./views/'
}))*/
const handlebarOptions = {
viewEngine: {
extName: '.hbs',
partialsDir: 'views',
layoutsDir: 'views',
defaultLayout: '',
},
viewPath: './views/',
extName: '.hbs',
};
transporter.use('compile', hbs(handlebarOptions));
const mailOptions = {
from: sender,
to: em,
subject: sub,
text: "Hello"
html: 'hi'
template: 'orders',
}
transporter.sendMail(mailOptions, function (err, info) {
if(err)
console.log(err)
else
console.log(info);
});
}))
export default mailerRouter;
server.js
import express from 'express';
import cors from 'cors';
import mongoose from 'mongoose';
import dotenv from 'dotenv';
import path from 'path';
import hbs from 'express-handlebars';
import orderRouter from './routers/orderRouter.js';
import mailerRouter from './mailer.js';
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
mongoose.connect(process.env.MONGODB_URL || 'mongodb://localhost/AM', {
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true,
});
app.use('/api/orders', orderRouter);
const __dirname = path.resolve();
app.use('/api/mailer', mailerRouter);
app.engine('hbs', hbs({
extname: 'hbs',
defaultLayout: false,
layoutDir:__dirname+'/backend/views/layouts/',
partialsDir: __dirname + '/backend/views/layouts',
}));
app.set('views', path.join( __dirname, '/backend/views/layouts'));
app.set('view engine', 'hbs');
app.get('/', (req, res) => {
res.send('Server is ready');
});
app.use((err, req, res, next) => {
res.status(500).send({ message: err.message });
});
const port = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Serve at http://localhost:${port}`);
});
Edit:
So, if I have:
...
const __dirname = path.resolve();
const emailTemplateSource = fs.readFileSync(path.join(__dirname, "backend/views/orders.hbs"), "utf8")
const mailOptions = {
from: sender,
to: em,
subject: sub,
text: '',
html: emailTemplateSource,
// template: emailTemplateSource,
...
The email body shows:
{{#each data.orderItems}}
{{name}}
{{/each}}
Instead of the names of the items. I have also tried adding const temp = handlebars.compile(emailTemplateSource) after const emailTemplateSource and then changing it to html: temp, but this sends a blank email. I have also tried adding these after template: , but no matter what I put there nothing seems to show up.
Additional Info:
console.log(emailTemplateSource)
Gives :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
</style>
</head>
<body>
{{#each data.orderItems}}
<div>
<h3>{{name}}</h1>
</div>
{{/each}}
</body>
</html>
And
const temp = handlebars.compile(emailTemplateSource) console.log(temp)
Gives: Function: ret] { _setup: [Function (anonymous)], _child: [Function (anonymous)]}
Greetings HERE Developer Support,
I'm seeing numerous Uncaught TypeErrors in the browser console coming from mapjs.bundle.js as I interact with the map in my React app.
I've reproduced the error with the minimal app below. Any insight is much appreciated.
package.json:
{
"type": "module",
"scripts": {
"start": "parcel index.html --open"
},
"devDependencies": {
"parcel": "^2.4.1"
},
"dependencies": {
"#here/maps-api-for-javascript": "^1.30.14",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Map App</title>
</head>
<body>
<div id="root" />
<script src="index.jsx" type="module"></script>
</body>
</html>
index.jsx:
import React from 'react';
import { createRoot } from 'react-dom/client';
import Map from './Map';
const rootElem = document.getElementById("root");
createRoot(rootElem).render(<Map />);
Map.jsx: (copied from the React tutorial at developer.here.com)
import React from 'react';
import H from "#here/maps-api-for-javascript";
export default class Map extends React.Component {
constructor(props) {
super(props);
// the reference to the container
this.ref = React.createRef();
// reference to the map
this.map = null;
}
componentDidMount() {
if (!this.map) {
// instantiate a platform, default layers and a map as usual
const platform = new H.service.Platform({
apikey: MyApiKey
});
const layers = platform.createDefaultLayers();
const map = new H.Map(
this.ref.current,
layers.vector.normal.map,
{
pixelRatio: window.devicePixelRatio,
center: {lat: 0, lng: 0},
zoom: 2,
},
);
this.map = map;
}
}
render() {
return (
<div
style={{ width: '300px', height:'300px' }}
ref={this.ref}
/>
)
}
}
Then run:
npm install && npm start
Please refer below steps, which tell how we can do the react setup.
Setup
For the fast setup of the new React application we will use the Create React App environment. It provides a fast way to get started building a new single-page application. Execute the npx runner as below (it requires Node >= 8.10 and npm >= 5.6):
npx create-react-app jsapi-react && cd jsapi-react
You can check the React setup page for the same.
We have an existing app, where the root "/" gets redirected to "/search" by default. It's been working fine via our next-redirects.js file:
async function redirects() {
return [
{
source: '/',
destination: '/search',
permanent: true,
},
];
}
I have to implement translation to the app, using next-i18next, so that we can have translated text + routing out of the box with NextJS. I have followed the steps in the next-i8next docs. I added the next-i18next.config.js file as:
const path = require('path');
module.exports = {
i18n: {
defaultLocale: 'en',
locales: ['en', 'es'],
},
localePath: path.resolve('./public/static/locales'), // custom path file route
};
And the next.config looks like:
const { i18n } = require('./next-i18next.config');
const defaultConfig = {
env: {
SOME_ENV,
},
images: {
deviceSizes: [980],
domains: [
'd1',
'd2',
],
},
i18n,
redirects: require('./next-redirects'),
webpack: (config, options) => {
if (!options.isServer) {
config.resolve.alias['#sentry/node'] = '#sentry/browser';
}
if (
NODE_ENV === 'production'
) {
config.plugins.push(
new SentryWebpackPlugin({
include: '.next',
ignore: ['node_modules'],
urlPrefix: '~/_next',
release: VERCEL_GITHUB_COMMIT_SHA,
})
);
}
return config;
},
};
module.exports = withPlugins([withSourceMaps], defaultConfig);
We have a custom _app file getting wrapped with the appWithTranslation HOC, and it's setup with the getInitialProps, per nextJS docs:
function MyApp({ Component, pageProps }) {
const [mounted, setMounted] = useState(false);
useEffect(() => {
// Remove the server-side injected CSS.
const jssStyles = document.querySelector('#jss-server-side');
if (jssStyles) {
jssStyles.parentNode.removeChild(jssStyles);
}
TagManager.initialize(tagManagerArgs);
setMounted(true);
}, []);
const Layout = Component.Layout || Page;
return (
<>
<Head>
<link rel="icon" href="/favicon.png" type="image/ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<AppProviders>
<Context {...pageProps}>
<Layout {...pageProps}>
<>
<Component {...pageProps} />
<Feedback />
<PageLoader />
</>
</Layout>
</Context>
</AppProviders>
</>
);
}
MyApp.getInitialProps = async ({ Component, ctx }) => {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps({ ctx });
}
const cookies = Cookie.parse(ctx?.req?.headers?.cookie || '');
if (Object.keys(cookies).length) {
const { token } = JSON.parse(cookies?.user || '{}');
let user = null;
if (token) {
const { data } = await get('api/users', { token });
if (data) {
user = data;
user.token = token;
}
}
pageProps.user = user;
pageProps.cart = cookies?.cart;
pageProps.defaultBilling = cookies?.defaultBilling;
pageProps.reservationEstimateItem = cookies?.reservationEstimateItem;
pageProps.reservationEstimate = cookies?.reservationEstimate;
}
return { pageProps };
};
export default appWithTranslation(MyApp);
And we have our _document file to handle some Emotion theming:
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
const styles = extractCritical(initialProps.html);
return {
...initialProps,
styles: (
<>
{initialProps.styles}
<style
data-emotion-css={styles.ids.join(' ')}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: styles.css }}
/>
</>
),
};
}
render() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
<script
type="text/javascript"
src="https://js.stripe.com/v2/"
async
/>
</body>
</Html>
);
}
}
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async ctx => {
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: App => props => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
At this point the redirect logic should continue to navigate to the search page which is setup like so:
export const SearchPage = () => {
const router = useRouter();
const { t } = useTranslation('search');
return (
<>
<Head>
<title>{`${t('searchTitle')}`}</title>
<meta
property="og:title"
content={`${t('searchTitle')}`}
key="title"
/>
<meta
name="description"
content={t('metaDescription')}
/>
</Head>
<Search />
</>
);
};
SearchPage.namespace = 'SearchPage';
export const getStaticPaths = () => ({
paths: [], // indicates that no page needs be created at build time
fallback: 'blocking' // indicates the type of fallback
});
export const getStaticProps = async ({ locale }) => ({
// exposes `_nextI18Next` as props which includes our namespaced files
props: {
...await serverSideTranslations(locale, ['common', 'search']),
}
});
export default SearchPage;
The search page has the getStaticPaths & getStaticProps functions, as needed on ALL page level files, per next-i18next.
Why does this setup no longer work with the redirect?
There are no errors in the terminal.
The network tab shows a 404 error on the root route of "/"
which implies the re-writing is not working. But what about the i18n makes this not behave?
Is it something in the _app or _document files?
If I navigate to /search directly, it loads fine, so the page routes are OK it seems.
Other notes:
NextJS "next": "^10.0.2",
next-i18next "next-i18next": "^7.0.1",
There seems to be some possible issues with Next & Locales...
https://github.com/vercel/next.js/issues/20488
https://github.com/vercel/next.js/issues/18349
My workaround is not pretty, but it works:
Delete the original next-rewrite
Add a new index.js page file that handles the redirect in the getServerSideProps:
const Index = () => null;
export async function getServerSideProps({ locale }) {
return {
redirect: {
destination: `${locale !== 'en' ? `/${locale}` : ''}/search`,
permanent: true,
},
};
}
export default Index;
when I use rollup configure vue3 environment ,i run it then use the component in the html file,it happen error
the code below
rollup.config.js this is rollup config file
const path = require('path')
const resolve = require('rollup-plugin-node-resolve')
const commonjs = require('rollup-plugin-commonjs')
const babel = require('rollup-plugin-babel')
const json = require('rollup-plugin-json')
const vue = require('rollup-plugin-vue')
const postcss = require('rollup-plugin-postcss')
const inputPath = path.resolve(__dirname,'./src/index.js')
const outputUmdPath = path.resolve(__dirname,'./dist/imooc.datav.js')
const outputEsPath = path.resolve(__dirname,'./dist/imooc.datav.es.js')
module.exports = {
input:inputPath,
output:[{
file:outputUmdPath,
format:'umd',
name:'imoocDatav',
globals: {
vue: 'Vue'
}
},{
file:outputEsPath,
format:'es',
globals: {
vue: 'Vue'
}
}],
plugins:[
vue(),
babel({
exclude:'node_modules/**',
presets: ["#vue/babel-preset-jsx"]
}),
resolve(),
commonjs(),
json(),
// vue(),
postcss({
plugins:[]
})
],
external:['vue']
}
Test.vue this is vue3 component
<template>
<div class="text">{{ aa }}</div>
</template>
<script>
export default {
name: 'Test',
setup() {
const aa = 'hello';
return {
aa,
};
},
};
</script>
<style lang="scss" scoped>
.text {
color: red;
}
</style>
index.js the code make an global component
import Test from './Test.vue'
export default function(Vue){
Vue.component(Test.name,Test);
}
index.html this is html file
<!DOCTYPE html>
<html>
<head>
<title>imooc datav libs example</title>
<script src="https://cdn.jsdelivr.net/npm/vue#3.0.0-beta.6/dist/vue.global.js"></script>
<script src="../dist/imooc.datav.js"></script>
</head>
<body>
<div id="app">
{{message}}
<test></test>
</div>
<script>
Vue.createApp({
setup(){
var message = 'hello world';
return {
message
}
}
}).use(imoocDatav).mount('#app');
</script>
</body>
</html>
vue.global.js:4877 TypeError: Cannot read property 'aa' of undefined
package.json dependencies:
"vue": "^3.0.0"
Change:
external:['vue']
to
external:['#vue']
This works for me
Using express-handlebars#5.2.0 and express#4.17.1 using node on windows and still cant get it to render in the body:
File Setup:
testapp.js
[views]
main.handlebars
[views][layouts]
test.handlebars
//testapp.js
const express = require('express');
const exhbr = require('express-handlebars');
const app = express();
const port = 3031;
app.engine('handlebars', exhbr({}));
app.use(express.static('public'));
app.set('view engine', 'handlebars');
app.get('/', (req, res) => {
res.render('main', { layout: 'test' });
});
app.listen(port, () => console.log(`App listening to port ${port}`));
<!--test.handlebars-->
<h1>Test</h1>
<!-- main.handlebars -->
<!DOCTYPE html>
<html lang="en">
<body>
{{{body}}}
</body>
</html>
Only <h1>Test</h1> is returned and hasn't been inserted into the body.
I have also tried the following just to make sure its looking in the right spots.
res.render('doesnt_exist');
Error: Failed to lookup view "doesnt_exist" in views directory "c:\wamp\www\rethinkdb_rest\views\"
res.render('main', { layout: "doesnt_exist" });
Error: ENOENT: no such file or directory, open 'c:\wamp\www\rethinkdb_rest\views\layouts\doesnt_exist.handlebars'
Looks like I was putting the main.handlebars and test.handlebars in the wrong directories.
File Setup should be:
testapp.js
[views]
test.handlebars
[views][layouts]
main.handlebars
And the render function in testapp.js should be:
//testapp.js
const express = require('express');
const exhbr = require('express-handlebars');
const app = express();
const port = 3031;
app.engine('handlebars', exhbr({}));
app.use(express.static('public'));
app.set('view engine', 'handlebars');
app.get('/', (req, res) => {
res.render('test', { layout: 'main' }); //<----fixed
});
app.listen(port, () => console.log(`App listening to port ${port}`));