Everything works in development, all images are found. But when I bundle my the files and upload to webhost, product img:s can't be found and returns error:
This is my .htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
This is my webpack.config.prod.js file:
// PRODUCTION
const webpack = require('webpack');
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const entry = {
app: path.join(process.cwd(), 'src/app.js')
}
const output = {
path: path.join(__dirname, 'dist'),
filename: 'bundle.min.js',
}
const plugins = [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
mangle: false,
compress: {
warnings: false
}
}),
new ExtractTextPlugin('bundle.css'), // creation of HTML files to serve your webpack bundles
new HtmlWebpackPlugin({
template: 'index-template.html'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'bundle',
filename: '[name].common.js'
})
]
const config = {
context: path.join(__dirname, 'src'),
entry: entry,
output: output,
devtool: "source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.join(__dirname, 'src'),
use: "babel-loader"
},
{
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'url-loader',
options: { limit: 10000, name: './img/[name].[ext]' } // Convert images < 10k to base64 strings (all in img folder)
}]
},
{
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: (loader) => [ require('autoprefixer')() ]
}
},
'sass-loader',
]
})
}
]
},
plugins: plugins,
externals: {
jquery: 'jQuery'
}
}
module.exports = config;
Images are imported in my product product component under lifecycle event "componentDidMount":
import React, { Component } from 'react';
import Modal from 'react-modal';
import PropTypes from 'prop-types';
// Custom styles for Modal image
const customStyles = {
content : {
top : '50%',
left : '50%',
right : 'auto',
bottom : 'auto',
marginRight : '-50%',
transform : 'translate(-50%, -50%)',
background : 'rgba(0, 0, 0, 0.8)',
width : '100vw',
height : '100vh',
display : 'flex',
justifyContent : 'center',
alignItems : 'center'
}
};
class ProductItem extends Component {
constructor(props) {
super(props);
this.state = {
modalIsOpen: false,
image: '',
previewImg: ''
};
this.openModal = this.openModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
// Set state object "modalIsOpen" to true when click on <ProductItem/> component
openModal() {
this.setState({
modalIsOpen: true
});
}
// Set state object "modalIsOpen" to false when click on <Modal/> component
closeModal() {
this.setState({
modalIsOpen: false
});
}
render(){
// Create variables for all <ProductItem/> description options. If <PoductItem/> object has props or state, render it. Otherwise return null.
var img = this.state.image ?
<img src={this.state.image} /> :
null;
const name = this.props.product.stocked ?
<h3>{this.props.product.name}</h3> :
<h3><span style={{color: 'red'}}>
{this.props.product.name}
</span></h3>;
var limited = this.props.product.limited ?
<p>begränsad upplaga: {this.props.product.limited} ex</p> :
null;
var available = this.props.product.available ?
<p>tillgängliga: {this.props.product.available} ex</p> :
null;
var price = this.props.product.price ?
<p>{this.props.product.price} kr</p> :
null;
var type = this.props.product.type ?
<p>{this.props.product.type}</p> :
null;
var size = this.props.product.size ?
<p>{this.props.product.size} cm</p> :
null;
var desc = this.props.product.desc ?
<p>{this.props.product.desc}</p> :
null;
var modalName = this.props.product.name ?
<h2>{this.props.product.name}</h2> :
null;
var modalDesc = this.props.product.desc ?
<h2>{this.props.product.desc}</h2> :
null;
return (
<div className="product hvr-sink" onClick={this.openModal}>
<Modal
isOpen={this.state.modalIsOpen}
onRequestClose={this.closeModal}
style={customStyles}
contentLabel="Modal image"
>
<div className="modal-box" onClick={this.closeModal}>
<div className="close" onClick={this.closeModal}>x</div>
<img className="modal-img" src={this.state.previewImg}/>
{modalName}
{modalDesc}
</div>
</Modal>
{img}
{name}
{type}
{limited}
{available}
{size}
{price}
{desc}
</div>
);
};
// Import all thumbnail + previewImg images and then() put them into state. If rejection occures catch() returns rejection reasen (err).
componentDidMount() {
import(`./images/${this.props.product.thumbnail}`).then(
(image) => this.setState({
image: image
})
).catch((err) => {
console.log('error thumbnail' + err);
});
import(`./images/${this.props.product.previewImg}`).then(
(previewImg) => this.setState({
previewImg: previewImg
})
).catch((err) => {
console.log('error previewImg' + err);
});
}
};
// Components expected proptypes
ProductItem.propTypes = {
product: PropTypes.object.isRequired
}
export default ProductItem;
All this works in development environment, images render no problem. Also, my background image and other img work that are being inserted via SASS:
.background-img {
position: fixed;
background: url(../images/main.jpg) no-repeat center center scroll;
background-size: cover;
z-index: 0;
}
or via "import" as ex "magdaImg":
It turned out to be a problem with my project not being located in the root.
Related
Basically what I need is generate one single file that contain all vendors and dependencies for each entry..
export default defineConfig({
plugins: [ react() ],
build: {
rollupOptions: {
input: {
popup: path.resolve(pagesDirectory, 'popup', 'index.html'),
background: path.resolve(pagesDirectory, 'background', 'index.ts'),
content_script: path.resolve(pagesDirectory, 'content_script', 'ContentScript.tsx')
},
output: {
entryFileNames: 'src/pages/[name]/index.js',
chunkFileNames: isDevelopment ? 'assets/js/[name].js' : 'assets/js/[name].[hash].js',
assetFileNames: (assetInfo) => {
const { dir, name: _name } = path.parse(assetInfo.name);
const assetFolder = getLastElement(dir.split('/'));
const name = assetFolder + firstUpperCase(_name);
return `assets/[ext]/${name}.chunk.[ext]`;
}
}
}
}})
In this case.. will be one file for popup, background and content_script
Here is one example of ContentScript.tsx file...
import * as React from 'react';
import { createRoot } from 'react-dom/client';
import Badge from './badge';
function init(query: string) {
const appContainer = document.querySelector('#search') as HTMLElement;
if (!appContainer) {
throw new Error('Can not find AppContainer');
}
const rootElement = document.createElement('div');
rootElement.setAttribute('id', 'web-answer-content-script');
appContainer.insertBefore(rootElement, appContainer.firstChild);
const root = createRoot(rootElement, {});
root.render(
<React.StrictMode>
<Badge query={query} />
</React.StrictMode>
);
}
const searchParameters = new URLSearchParams(window.location.search);
if (searchParameters.has('q')) {
const query = searchParameters.get('q');
init(query);
}
import MessageSender = chrome.runtime.MessageSender;
function handleMessageReceived(message: string, sender: MessageSender) {
console.log('>>> MESSAGE RECEIVED', message, sender);
}
chrome.runtime.onMessage.addListener(handleMessageReceived);
With this configuration I'm getting this..
and my content_scripts/index.js ..
import { j as n, c as a, r as c } from '../../../assets/jsx-dev-runtime.a077470a.js';
// ..rest of the code...
As you can see.. I don't want this import... statement ..
I'd like to use Ckeditor in my Laravel/Inertia project and i can't get it to work. I found a tutorial from LaraTips, but that was written for VueJS-2. I am working with the lastest version Inertia which uses VueJS-3.
I want to use Ckeditor in a separate component, and it (sort of) works, but i can't get the old data to show in the editor. I get an error "Uncaught (in promise) TypeError: Cannot read property 'setData' of undefined at Proxy.modelValue (app.js:29)"
What am i doing wrong?
This is my component:
<template>
<ckeditor :editor="editor" v-model="text" :config="editorConfig"></ckeditor>
</template>
<script>
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
export default {
data() {
return {
text: "",
editor: ClassicEditor,
editorConfig: {
// The configuration of the editor.
},
}
},
props: {
modelValue: {}
},
setup() {
},
watch: {
modelValue: {
immediate: true,
handler(modelValue) {
this.text = modelValue;
}
},
text(text) {
this.$emit('update:modelValue', text);
}
},
}
</script>
Any suggestions??
I am doing the same tutorial (i am using vueJS-3).
this may work for you:
in app.js include CKEditor:
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) => require(`./Pages/${name}.vue`),
setup({ el, app, props, plugin }) {
return createApp({ render: () => h(app, props) })
.use(plugin)
.use( CKEditor)
.mixin({ methods: { route } })
.mount(el);
},
});
In Components/CkEditor.vue check what are you emitting
look for this this.$emit("input", text);
<template>
<ckeditor :editor="editor" v-model="text" :config="editorConfig"></ckeditor>
</template>
<script>
import ClasicEditor from "#ckeditor/ckeditor5-build-classic";
export default {
props: {
value: {},
},
data() {
return {
text: "",
editor: ClasicEditor,
editorConfig: {
// The configuration of the editor.
},
};
},
watch: {
value:{
inmediate: true,
handler(value){
this.text = value;
}
},
text(text) {
this.$emit("input", text);
},
},
};
</script>
let me know if that worked for you
I looked at the answer here, and below is what worked for me:
Hope this helps! :)
I am using laravel/inertia with vue 3.
app.js
import './bootstrap';
import '../css/app.css';
import { createApp, h } from 'vue';
import { createInertiaApp } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers';
import { ZiggyVue } from '../../vendor/tightenco/ziggy/dist/vue.m';
import { createPinia } from 'pinia';
import { _t } from './Utilities/translations';
import CKEditor from '#ckeditor/ckeditor5-vue';
const appName =
window.document.getElementsByTagName('title')[0]?.innerText || 'Laravel';
createInertiaApp({
title: (title) => `${title} - ${appName}`,
resolve: (name) =>
resolvePageComponent(
`./Pages/${name}.vue`,
import.meta.glob('./Pages/**/*.vue')
),
setup({ el, app, props, plugin }) {
const vue_app = createApp({ render: () => h(app, props) });
vue_app.use(plugin);
vue_app.use(ZiggyVue, Ziggy);
vue_app.use(createPinia());
// Register all base components globally
const components = import.meta.globEager('./Components/Base/*.vue');
for (const path in components) {
let componentName;
if (path.split) {
const split_componentName = path.split('/').pop();
if (split_componentName) {
componentName = split_componentName.replace(/\.\w+$/, '');
vue_app.component(componentName, components[path].default);
}
}
}
vue_app.config.globalProperties.$_t = _t;
vue_app.use(CKEditor);
vue_app.mount(el);
return vue_app;
}
});
InertiaProgress.init({ color: '#4B5563' });
CKEditor Component:
<template>
<div id="app">
<ckeditor
v-model="editor_data"
:editor="editor"
:config="editor_config"
></ckeditor>
</div>
</template>
<script setup lang="ts">
import { reactive, ref } from '#vue/reactivity';
import * as editor from '#ckeditor/ckeditor5-build-classic';
const editor_data = ref('');
const editor_config = {};
</script>
I am attempting to create a SSR react app with Firebase hosting and Cloud Functions. My components are using className to declare classes. My server-rendered html does not include these, it only has the data-reactid elements.
It is not until the bundle.js is loaded that the real class="example-class" is loaded.
I do not want to wait for the bundle.js to download before the classes are loaded. I'd rather not code with both
class="kitten-image" className="kitten-image"
because that seems like a waste. I have not been able to find anything that either transforms the CSS files to have the data-reactid identifiers, or to automatically include the class="kitten-image" on the server-side during the compile process with babel.
Overview: My server-side compiled code injects the babel compiled react components into an index.html template file, which is sent via express app on http request on Firebase functions. The index.html file includes hard-coded references to the webpack processed styles.css and bundle.js in the firebase hosting public folder.
Thus, my server-side rendered HTML should immediately be able to reference the styles.css sheet - however, the classes are not in the html until the bundle.js is loaded (which is the problem).
Server-side rendered HTML before bundle.js loads
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>React Server Side Rendering - Firebase Hosting</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="root"><div data-reactroot="" data-reactid="1" data-react-checksum="1473597379"><h1 data-reactid="2">Hello World!</h1><p data-reactid="3"><!-- react-text: 4 -->This is a kitten: <!-- /react-text --><br data-reactid="5"/><img src="/media/kitten.jpg" alt="Kitten" data-reactid="6"/></p></div></div>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
HTML after bundle.js loads
Note that class="kitten-image" has been added.
<!DOCTYPE html>
<html><head>
<meta charset="UTF-8">
<title>React Server Side Rendering - Firebase Hosting</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="root"><div data-reactroot="" data-reactid="1"><h1 data-reactid="2">Hello World!</h1><p class="intro" data-reactid="3"><!-- react-text: 4 -->This is a kitten: <!-- /react-text --><br data-reactid="5"><img src="/media/kitten.jpg" alt="Kitten" class="kitten-image" data-reactid="6"></p></div></div>
<script type="text/javascript" src="bundle.js"></script>
</body></html>
Folder Structure
App Component Example
see className
import React, { Component } from 'react';
import kitten from "./kitten.jpg";
import "./App.scss";
class App extends Component {
render() {
return (
<div class="main">
<h1>Hello World!</h1>
<p className="intro">This is a kitten: <br /><img src={kitten} alt="Kitten" className="kitten-image" /></p>
</div>
);
}
}
export default App;
Babel Compiled Component
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
var kitten = "/media/kitten.jpg";
var App = function (_Component) {
_inherits(App, _Component);
function App() {
_classCallCheck(this, App);
return _possibleConstructorReturn(this, (App.__proto__ || Object.getPrototypeOf(App)).apply(this, arguments));
}
_createClass(App, [{
key: "render",
value: function render() {
return _react2.default.createElement(
"div",
{ "class": "main" },
_react2.default.createElement(
"h1",
null,
"Hello World!"
),
_react2.default.createElement(
"p",
null,
"This is a kitten: ",
_react2.default.createElement("br", null),
_react2.default.createElement("img", { src: kitten, alt: "Kitten" })
)
);
}
}]);
return App;
}(_react.Component);
exports.default = App;
Server index.js
import React from "react";
import { renderToString } from "react-dom/server";
import App from "../shared/App";
import express from "express";
import * as fs from "fs";
import * as functions from "firebase-functions";
const index = fs.readFileSync(__dirname + '/../../index.template.html', 'utf8');
const app = express();
app.get('**', (req, res) => {
const html = renderToString(<App />);
const finalHtml = index.replace('<!-- ::APP:: -->', html);
res.set('Cache-Control', 'public, max-age=600, s-maxage=1200');
res.send(finalHtml);
});
export let ssrapp = functions.https.onRequest(app);
//app.listen(3006, () => { console.log('Listening on 3006.'); });
Server index.js babel compiled
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ssrapp = undefined;
var _react = require("react");
var _react2 = _interopRequireDefault(_react);
var _server = require("react-dom/server");
var _App = require("../shared/App");
var _App2 = _interopRequireDefault(_App);
var _express = require("express");
var _express2 = _interopRequireDefault(_express);
var _fs = require("fs");
var fs = _interopRequireWildcard(_fs);
var _firebaseFunctions = require("firebase-functions");
var functions = _interopRequireWildcard(_firebaseFunctions);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var index = fs.readFileSync(__dirname + '/../../index.template.html', 'utf8');
var app = (0, _express2.default)();
app.get('**', function (req, res) {
var html = (0, _server.renderToString)(_react2.default.createElement(_App2.default, null));
var finalHtml = index.replace('<!-- ::APP:: -->', html);
res.set('Cache-Control', 'public, max-age=600, s-maxage=1200');
res.send(finalHtml);
});
var ssrapp = exports.ssrapp = functions.https.onRequest(app);
//app.listen(3006, () => { console.log('Listening on 3006.'); });
Webpack
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const autoprefixer = require("autoprefixer");
const extractSass = new ExtractTextPlugin({
filename: "public/styles.css",
disable: process.env.NODE_ENV === "development"
});
// Webpack settings unique to browser-side script
const browserConfig = {
entry: './src/browser/index.js',
devtool: "source-map",
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: [/\.svg$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: "file-loader",
options: {
name: "public/media/[name].[ext]",
publicPath: url => url.replace(/public/, "")
}
},
{
test: /\.scss$/,
use: extractSass.extract({
use: [
{ loader: 'css-loader', options: { sourceMap: true } },
{
loader: 'postcss-loader',
options: {
// Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677
ident: 'postcss',
sourceMap: true,
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
{ loader: 'sass-loader', options: { sourceMap: true } }
],
// use style-loader in development
fallback: "style-loader"
})
}
]
},
plugins: [
extractSass
],
output: {
filename: './public/bundle.js',
path: __dirname
}
}
module.exports = [browserConfig];
I was initially using Babel because I was having issues compiling via webpack with the Google Cloud / firebase modules. It was trying to bundle in everything unnecessarily.
I created a separate webpack server-side configuration. This does a few things to work correctly.
1.I'm using the "webpack-node-externals" package which is designed to exclude node modules for backend compilation. Without this, my generated JS file was enormous. My backend has a whole node_modules folder, so it does not need these items bundled.
2.I added the false statements to __dirname and __filename - I don't know what this does or how it works, but it fixed my issue with opening and reading my html template file server-side.
3.The file-loader does not actually copy the files, with emit: false
The Real Fix: The .scss tester uses css-loader/locals This was key! It generates the correct class names on the server and places them in the components when rendering! It also does not bundle / copy and files in this configuration, since the browser side config does that.
I was using the following plugin in my .babelrc file with the babel compile method. This breaks the image / file transfer process in webpack and must be removed from .babelrc
"plugins": [["transform-assets-import-to-string", {
"baseDir": "",
"baseUri": "/media"
}]],
Revised Webpack
const serverConfig = {
entry: "./src/server/index.js",
target: "node",
externals: [nodeExternals()], // exclude node_modules
node: {
__dirname: false,
__filename: false
},
output: {
filename: "./functions/src/server/server.js",
libraryTarget: "commonjs2"
},
module: {
rules: [
{
test: [/\.svg$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: "file-loader",
options: {
name: "public/media/[name].[ext]",
publicPath: url => url.replace(/public/, ""),
emit: false
}
},
{
test: /\.scss$/,
use: [
{ loader: 'css-loader/locals' },
{ loader: 'sass-loader' }
]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader"
}
]
}
};
Given that these are the dependencies that I am using:
"react-hot-loader": "3.0.0-beta.7",
"webpack": "2.6.1",
"webpack-dev-middleware": "^1.11.0",
"webpack-hot-middleware": "^2.18.1",
"webpack-merge": "^4.1.0"
Error
patch.js:5
Uncaught ReferenceError: development is not defined
at Object.defineProperty.value (patch.js:5)
at __webpack_require__ (bootstrap 921586e…:659)
at fn (bootstrap 921586e…:85)
at Object.options.path (patch.js:1)
at __webpack_require__ (bootstrap 921586e…:659)
at fn (bootstrap 921586e…:85)
at Object.<anonymous> (process-update.js:132)
at __webpack_require__ (bootstrap 921586e…:659)
at validateFormat (bootstrap 921586e…:708)
at bootstrap 921586e…:708
You might want to either take a look at this repo
webpack-config
const FILE_PATHS = {
entry: path.resolve('./src/index.js'),
reactHotLoader: 'react-hot-loader/patch',
hmrEntry: 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000', // this is from the webpack-hot-middleware docs
output: '/' // this is the path used by webpack-dev-middleware, the docs say no real path is required, just pass in `/`
}
const devOnly = {
entry: FILE_PATHS.entry,
output: {
path: '/',
publicPath: '/assets/',
filename: 'bundle.js'
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.jsx?$/,
use: [
{
loader: 'babel-loader'
}
],
// react-hot-loader asks to include src and exclude node_modules in https://github.com/gaearon/react-hot-loader/blob/master/docs/Troubleshooting.md
include: path.resolve('./src'),
exclude: /node_modules/
},
{
test: /\.json$/,
use: [
{
loader: 'json-loader'
}
]
},
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader'
}
]
}
]
},
plugins: [
new DefinePlugin({
'process.env.NODE_ENV': 'development'
})
]
}
const hmr = {
entry: [FILE_PATHS.reactHotLoader, FILE_PATHS.hmrEntry, FILE_PATHS.entry],
plugins: [new HmrPlugin(), new NoErrorsPlugin()],
devServer: {
hot: true
}
}
const dev = merge(devOnly, hmr)
module.exports = {dev}
Express Server
// process.env.NODE_ENV = 'development'
const express = require('express')
const webpack = require('webpack')
const historyApiFallback = require('connect-history-api-fallback')
const normalizeAssets = assets => {
return Array.isArray(assets) ? assets : [assets]
}
const getLinks = assets => {
const styles = assets.filter(path => path.endsWith('.css'))
const links = styles.map(path => `<link rel="stylesheet" href="${path}" />`)
return links.join('\n')
}
const publicPath = '/assets/'
const getScripts = assets => {
const js = assets.filter(path => path.endsWith('.js'))
const scripts = js.map(path => `<script src="${path}"></script>`)
return scripts.join('\n')
}
const devMiddlewareConfig = {
serverSideRender: true,
stats: 'normal',
publicPath: publicPath,
watchOptions: {
poll: 1000,
aggregateTimeout: 300
}
}
const hotMiddlewareConfig = {
reload: true,
overlay: true
}
const devMiddlewareCreator = require('webpack-dev-middleware')
const hotMiddlewareCreator = require('webpack-hot-middleware')
const options = require('./webpack.config')
const {dev: devConfig} = options
const compiler = webpack(devConfig)
const devMiddleware = devMiddlewareCreator(compiler, devMiddlewareConfig)
const hotMiddleware = hotMiddlewareCreator(compiler, hotMiddlewareConfig)
const app = express()
app.use(devMiddleware)
app.use(hotMiddleware)
app.use(express.static(__dirname + '/public'))
app.use((req, res) => {
const stats = res.locals.webpackStats.toJson()
const assets = normalizeAssets(stats.assetsByChunkName.main)
const styles = getLinks(assets)
const scripts = getScripts(assets)
res.send(
`
<!DOCTYPE html>
<html>
<head>
<title>Webpack is crazy</title>
${styles}
</head>
<body>
<div id="app">
</div>
${scripts}
</body>
</html>
`
)
})
// app.use(historyApiFallback)
app.listen(3000, err => {
if (!err) {
console.log('Server is listening on port 3000')
}
})
The error is caused by this part of your configuration:
new DefinePlugin({
'process.env.NODE_ENV': 'development'
})
To quote the documentation:
Note that because the plugin does a direct text replacement, the value given to it must include actual quotes inside of the string itself. Typically, this is done either with either alternate quotes, such as '"production"', or by using JSON.stringify('production').
If you replace it with, for example, the following, it should work:
new DefinePlugin({
'process.env.NODE_ENV': '"development"'
})
My code wont compile for some reason. The weird thing is that is will work when I use the in browser interpreter.
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script src="https://unpkg.com/react#15/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#15/dist/react-dom.min.js"></script>
React code:
var Cookies = require('cookies');
var cookieParser = require('cookie-parser');
var name = document.getElementById('name').innerHTML;
//var name = req.user.name;
var start = false;
var Assets = React.createClass({
getInitialState: function(){
return({
assets: [],
secondsElapsed: 0
});
},
tick: function() {
//this.setState({secondsElapsed: this.state.secondsElapsed + 1});
if(start === true){
console.log(name);
var myHeaders = new Headers();
var token = new Cookies(req,res).get('access_token');
myHeaders.append('acess_token', token);
var myInit = { method: 'GET',
headers: myHeaders};
fetch('/api/user/all/?name='+name, myInit).then(function(data){
return data.json();
}).then( json => {
this.setState({
assets: json
});
});
}
},
componentDidMount: function() {
this.interval = setInterval(this.tick, 1000);
},
componentWillUnmount: function() {
clearInterval(this.interval);
},
render: function(){
var assets = this.state.assets;
assets = assets.map(function(asseti,index){
return(
asseti.map(function(asset, index){
return(
<li key={index}>
<span className={asset.active}></span>
<span>{asset.name}</span>
<span >{asset.description}</span>
<span>{asset.location.coordinates[0]}{asset.location.coordinates[1]}</span>
</li>
)
})
)
});
return(
<div>
<form onSubmit={this.handleSubmit}>
<input type="submit" value="Find assets" />
</form>
{assets}
</div>
);
},
handleSubmit: function(e){
e.preventDefault();
start = true;
// name = this.refs.name.value;
fetch('/api/user/all/?name='+name).then(function(data){
return data.json();
}).then( json => {
this.setState({
assets: json
});
});
}
});
ReactDOM.render(<Assets />, document.getElementById('assets'));
Webpack.config.js:
var path = require('path');
module.exports = {
entry: path.resolve(__dirname, 'puplic') + '\\js\\baseReact.js',
output: {
path: path.resolve(__dirname, 'dist') + '/app',
filename: 'bundle.js',
publicPath: '/app/'
},
module: {
loaders: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'public/js'),
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0']
}
},
{
test: /\.css$/,
loader: 'style-loader!css-loader'
}
]
},
devServer: {
historyApiFallback: true
}
};
Error:
ERROR in ./puplic/js/baseReact.js
Module parse failed: C:\Users\test\Documents\GPSTracker\puplic\js\baseReact.js Unexpected token (
53:14)
You may need an appropriate loader to handle this file type.
| asseti.map(function(asset, index){
| return(
| <li key={index}>
| <span className={asset.active}></span>
| <span>{asset.name}</span>
I figure I must be doing something dumb like missing something as it runs in browser which is weird. Does that gloss over some errors as it is interpreted as opposed to been compiled before been run?
Based on the comments, you may be missing the fetch import. Fetch is not readily available in all browsers.
The npm package whatwg-fetch mentions specifically how to get fetch working in a webpack-enabled environment.
Installation
npm install whatwg-fetch --save
or
bower install fetch.
You will also need a Promise polyfill for older browsers. We recommend
taylorhakes/promise-polyfill for its small size and Promises/A+
compatibility.
For use with webpack, add this package in the entry configuration
option before your application entry point:
entry: ['whatwg-fetch', ...]
For Babel and ES2015+, make sure to
import the file (in your react-components):
import 'whatwg-fetch'
Also, looking at your code, which is deviating a tad from regular javascript style guides in terms of spacings, I'd look into getting eslint up and running in your environment for better feedback for errors like these. If you had eslint enabled, you'd get fetch is undefined as soon as you tried something like this without importing fetch first.
Another personal note from me, try just importing whatwg-fetch in your file, before tampering with your webpack config. You may not need to add it as an entry.
Best of luck!