I have been given a chatbot project in javascript using webpack and for some reason I am unable to make it run succesfully! Web pack is running by starting the script with npm start but the page is blank.
Here is the index.html
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<title>Chatbot</title>
<script src="assets/lib/jquery.min.js"></script>
<script></script>
</head>
<body>
<div id="app">
</div>
</body>
</html>
this is index.js
import Dialogflow from './dialogflow';
import './assets/styles/main.css';
console.log("helloooo 2")
if (!$) {
console.error("Bot: This module requires jQuery.");
}
let default_messages = {
header: {
'en-US': 'Hi! How can I help you?',
},
inputPlaceholder: {
'fi': 'Kirjoita jotain (paina enter lähettääksesi)',
'en-US': 'Write something (press Enter to send)',
}
}
let lang = document.documentElement.lang;
class Bot{
renderHumanMessage(message) {
if (!message) {
return;
}
$('#sc-chb-response').append(`
<div class="sc-chb-conversationPlaceholder">
<div class="sc-chb-userRequest">
<div class="sc-chb-userReply">
<div class="sc-chb-chatBubbleHuman"></div>
` + message + `
</div>
</div>
<div class="sc-chb-usrImg">
<div class="sc-chb-responseIcon">
<div class="sc-chb-iconUserImg"></div>
</div>
</div>
</div>
`);
}
addOptionClickListener(chatBot) {
return function(e) {
$('#sc-chb-inputMessage').val($(this).attr('data-option'));
chatBot.sendMessage();
};
}
open() {
if (!this.hasToggleButton) {
$('#sc-chb-chat-box-toggle').hide();
} else {
$('.sc-chb-chatState').hide();
$('#sc-chb-chatStateClose').show();
}
$('#sc-chb-chat-box').show();
if (this.triggerWelcomeEvent === true) {
// Request the welcome message by triggering the welcome event
Dialogflow.triggerEvent('Welcome').then(res => {
this.renderBotMessage(res);
});
this.triggerWelcomeEvent = false;
}
}
toggle() {
if (this.isOpen()) {
this.close();
} else {
this.open();
}
}
isOpen() {
return $('#sc-chb-chat-box').is(":visible");
}
renderFulfillmentText(text) {
let processedText = text.replace(new RegExp('\n', 'g'), '<br>');
// renders [[text]] to a clickable chat bubble
processedText = processedText.replace(/\[\[([^\[\]]+)\]\](<br>)?/g, '<div class="sc-chb-chatbotOption" data-dialogflow="\$1" data-option="\$1">\$1</div>');
// renders {{{name|url}}} as name
return processedText.replace(/\{\{([^\{\}]+)\|([^\{\}]+)\}\}/g, '\$1');
}
}
export { Bot};
and there is an example.js file that shows how to use the bot class:
import { Bot} from './Bot';
let bot = new Bot({
"baseUrl": "xxxxx"
});
bot.init();
Webpack config:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: {minimize: true}
}
]
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader",
{
loader: 'postcss-loader',
options: {
config: {
path: './postcss.config.js'
}
}
}
]
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'url-loader?name=assets/[name].[hash].[ext]'
}
]
},
devServer: {
contentBase: 'src/',
// historyApiFallback: true,
// disableHostCheck: true,
port: process.env.PORT || 8080,
// host: '0.0.0.0',
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
require('autoprefixer'),
new MiniCssExtractPlugin({
filename: "main.css",
chunkFilename: "main.css"
}),
new CopyWebpackPlugin([
{ from: 'src/assets', to: 'assets' },
]),
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
library: 'sc-chatbot-frontend',
libraryTarget: 'umd'
},
externals: {
'jquery': 'jQuery',
'url-loader': 'url-loader'
}
};
I am not sure from where do I use this example.js or where does this needs to be defined? I tried to inlclude to index.html but still page is blank.
Basically i run npm start and a blank page appears, it should show the chatbot instead!
Related
I'm trying to setup vue app using webpack.
This is my webpack.config.js file:
const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
"Shared/global": './ClientApp/src/js/Shared/global.js',
},
output: {
filename: 'js/[name].entry.js',
path: path.resolve(__dirname, 'dist'),
publicPath: ""
},
devtool: 'source-map',
mode: 'development',
module: {
rules: [
{
test: /\.css$/,
use: [{ loader: MiniCssExtractPlugin.loader }, 'css-loader'],
},
{
test: /\.(eot|woff(2)?|ttf|otf|svg)$/i,
type: 'asset'
},
{
test: /\.js$/,
use: {
loader: "babel-loader",
},
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css"
})
]
};
And this is the entry file:
import {createApp} from 'vue';
import { createStore } from 'vuex'
const _ = require('lodash')
In my layout.html I call global.entry.js as such:
<body>
<div id="layoutApp">
<h1>HELLO</h1>
</div>
</body>
<script type="module" src="/dist/js/Shared/global.entry.js" defer></script>
<script src="/ClientApp/src/js/Shared/layout.js" defer></script>
Then I try to use vue in layout.js:
const layoutApp = createApp({
mounted(){
console.log("layout is mounted VUE")
},
});
layoutApp.mount("#layoutApp")
var array = [1];
var other = _.concat(array, 2, [3], [[4]]);
console.log(other);
But in chrome console it said createApp is not defined. But if I run only lodash code, lodash works fine. I cant figure out what I did wrong. Any help would be very helpful
so I'm creating a ReactJS app and configuring webpack for it.
below's my webpack config:
webpack.config.js
const webpack = require('webpack');
const HtmlWebPackPlugin = require( 'html-webpack-plugin' );
const path = require( 'path' );
const dotenv = require('dotenv');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const env = dotenv.config().parsed;
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
module.exports = {
context: __dirname,
entry: ['./src/js/index.js','./src/sass/index.scss'],
output: {
path: path.resolve( __dirname, 'dist' ),
filename: 'main.js',
publicPath: '/',
},
devtool: 'eval-source-map',
devServer: {
historyApiFallback: true,
contentBase: path.join(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: [/node_modules/],
query: {
presets: ['#babel/react', "#babel/preset-env"]
}
},
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: [/node_modules/],
query: {
presets: ['#babel/react', "#babel/preset-env"]
}
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg|webp)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true, // webpack#1.x
disable: true, // webpack#2.x and newer
},
},
],
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: path.resolve( __dirname, 'public/index.html' ),
filename: 'index.html',
}),
new webpack.ProvidePlugin({
"React": "react",
}),
new CopyWebpackPlugin({
patterns: [
{ from: 'public/assets' }
]
}),
new webpack.DefinePlugin(envKeys),
]
};
It was all going well until I realized that all my buttons aren't working, I checked all the functions and the syntax to make sure if I get it wrong, but turns out I am making no mistake about it
here's the function to my button:
const submitMail = e => {
console.log('here')
alert('here')
e.preventDefault()
e.stopPropagation()
e.nativeEvent.stopImmediatePropagation();
console.log('test')
}
I tried to call it in my test button, but it wouldn't work, it sent no alert, it won't even log all my console.logs
<button onClick={e => submitMail(e)}>test</button>
I also tried to put them in my form to trigger it at onSubmit along with another button inside just to see if it triggers the "console.log" which is also not working:
<form onSubmit={e => submitMail(e)}>
<input id="banner-text-input-email-input-wrapper-email-input" placeholder="Enter your email here"/>
<input id="banner-text-input-email-input-wrapper-submit-input" onClick={()=>console.log('hi')} type="button" value="Button Value"/>
</form>
NOTE:
I've tried to run the normal react app:
react-script start
and all the buttons are working!! at this point, I can only think that the reason it's not working is because of my webpack config, here's also my webpack command just in case:
webpack serve --open --mode=development --config=webpack.config.js
--hot
Instead of
<button onClick={e => submitMail(e)}>test</button>
did you try to use
<button onClick={submitMail}>test</button>
It will implicitly send the event if I'm not mistaken...
okay, it turns out, I'm very silly at this thing, I'm very new to webpacks, so I thought I needed to put
<script type="text/javascript" src="main.js"></script>
in my public/index.html file
after I deleted that part, it all went well.
Seems this would be more straightforward, but I am stumped. My React app is being served with Webpack and if I open up the localhost in an Incognito browser (or refresh a regular tab without cache) the content appears. But otherwise I get these errors in my inspector:
src/index.js and public/index.html files are like a basic Create React App config, like so:
src/index.js:
import React from 'react';
import ReactDOM from "react-dom";
import App from "./components/App";
ReactDOM.render(<App />, document.getElementById('root'));
public/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Index</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
and the Webpack is as follows:
const Dotenv = require('dotenv-webpack')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const config = {
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.css']
},
module: {
rules: [
{
test: /\.(tsx?|jsx?)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
rootMode: 'upward'
}
}
]
},
{
enforce: 'pre',
test: /\.js$/,
exclude: /node_modules/,
loader: 'source-map-loader'
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader'
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
}
]
},
node: {
fs: 'empty'
},
plugins: [
new Dotenv({
path: './.env',
systemvars: true
}),
new ForkTsCheckerWebpackPlugin({ eslint: true })
]
}
module.exports = env => {
const styleRule = {
test: /\.(scss|css)$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
const htmlPluginConfig = { template: 'public/index.html', inject: true }
config.module.rules.push(styleRule)
config.plugins.push(new HtmlWebpackPlugin(htmlPluginConfig))
config.devtool = 'inline-source-map'
config.devServer = {
contentBase: './src',
overlay: true,
port: 8080
}
return config
}
I know something is jacked, but can't put my finger on it.
I just spent 3 hours putting this line:
exclude: ['./src/assets/sass']
in 20 different places. Please tell me where this should go?
Here is my current setup for the css-loader (util.js):
'use strict'
const path = require('path')
const config = require('../config')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const packageConfig = require('../package.json')
exports.assetsPath = function (_path) {
const assetsSubDirectory = process.env.NODE_ENV === 'production'
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory
return path.posix.join(assetsSubDirectory, _path)
}
exports.cssLoaders = function (options) {
options = options || {}
const cssLoader = {
loader: 'css-loader',
options: {
sourceMap: options.sourceMap
}
}
const postcssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: options.sourceMap
}
}
// generate loader string to be used with extract text plugin
function generateLoaders (loader, loaderOptions) {
const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader]
if (loader) {
loaders.push({
loader: loader + '-loader',
// exclude: ['./src/assets/sass'],
options: Object.assign({}, loaderOptions, {
sourceMap: options.sourceMap
})
})
}
// Extract CSS when that option is specified
// (which is the case during production build)
if (options.extract) {
return ExtractTextPlugin.extract({
use: loaders,
fallback: 'vue-style-loader'
})
} else {
return ['vue-style-loader'].concat(loaders)
}
}
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
return {
css: generateLoaders(),
postcss: generateLoaders(),
less: generateLoaders('less'),
sass: generateLoaders('sass', { indentedSyntax: true }),
scss: generateLoaders('sass'),
stylus: generateLoaders('stylus'),
styl: generateLoaders('stylus')
}
}
// Generate loaders for standalone style files (outside of .vue)
exports.styleLoaders = function (options) {
const output = []
const loaders = exports.cssLoaders(options)
for (const extension in loaders) {
const loader = loaders[extension]
output.push({
test: new RegExp('\\.' + extension + '$'),
exclude: ['./src/assets/sass'],
use: loader
})
}
return output
}
exports.createNotifierCallback = () => {
const notifier = require('node-notifier')
return (severity, errors) => {
if (severity !== 'error') return
const error = errors[0]
const filename = error.file && error.file.split('!').pop()
notifier.notify({
title: packageConfig.name,
message: severity + ': ' + error.name,
subtitle: filename || '',
icon: path.join(__dirname, 'logo.png')
})
}
}
Here is what my base webpack file looks like:
'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')
function resolve (dir) {
return path.join(__dirname, '..', dir)
}
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: ['babel-polyfill','./src/main.js']
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src'),
}
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')],
},
// {
// test: /\.scss$/,
// exclude: ['./src/assets/sass']
// },
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
Here is the vue-webpack file:
'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction
? config.build.productionSourceMap
: config.dev.cssSourceMap
module.exports = {
loaders: utils.cssLoaders({
sourceMap: sourceMapEnabled,
extract: isProduction
}),
cssSourceMap: sourceMapEnabled,
cacheBusting: config.dev.cacheBusting,
transformToRequire: {
video: ['src', 'poster'],
source: 'src',
img: 'src',
image: 'xlink:href'
}
}
Presumably this line should go in one of these files unfortunately it is not preventing webpack from attempting to build it (and therefore failing to do so)
Turns out after much experimentation that if I removed this line from the first snippet:
scss: generateLoaders('sass'),
The reason seems to be that even though the files in this directory are never used in my project, the loader attempts to load them because of the file name, so by not having a loader it does not attempt that and no other errors are thrown since the file is not used.
Presumably if one wanted to keep the loader and exclude a specific directory then you would need to put in a condition on this section in the first snippet:
for (const extension in loaders) {
const loader = loaders[extension]
//enter your condition here, i.e. if(loader === something) then push an object
// with "exclude"
output.push({
test: new RegExp('\\.' + extension + '$'),
exclude: ['./src/assets/sass'],
use: loader
})
}
I have a react application that I'm trying to extract the css into separate files but I'm having some issues here. I'm suing the MiniCssExtractPlugin for this. My current webpack configuration included below works fine when I include my own css files but it fails when I include my bootstrap.css from node_modules.
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import MyApp from './scenes/MyApp/MyApp'
import 'bootstrap/dist/css/bootstrap.css'
import './index.css'
import './assets/stylesheets/scenes.scss'
ReactDOM.render(<MyApp />, document.getElementById('root'))
webpack.config.js
const appConstants = function() {
switch (process.env.NODE_ENV) {
case 'local':
const localConfig = require('./config/local');
return localConfig.config();
case 'development':
const devConfig = require('./config/development');
return devConfig.config();
case 'production':
default:
const prodConfig = require('./config/production');
return prodConfig.config();
}
};
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const webpack = require('webpack');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const htmlWebpackPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html",
hash: true
});
let webpackConfig = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(css|scss)$/,
exclude: [/node_modules/],
include: [/node_modules\/bootstrap\/dist/],
use: [
{
loader: process.env.NODE_ENV !== 'local' ? MiniCssExtractPlugin.loader : 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(pdf|jpg|png|gif|svg|ico)$/,
exclude: [/node_modules/],
use: [
{
loader: 'file-loader'
},
]
},
{
test: /\.(woff|woff2|eot|ttf|svg|otf)$/,
exclude: [/node_modules/],
use: {
loader: 'url-loader?limit100000'
}
}
]
},
entry: [ "#babel/polyfill", "./src/index.js"],
output: {
publicPath: appConstants().DS_BASENAME ? JSON.parse(appConstants().DS_BASENAME) : '/'
},
optimization: {
splitChunks: {
chunks: 'all'
}
},
plugins: [
htmlWebpackPlugin,
new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /en/),
new BundleAnalyzerPlugin({
analyzerMode: 'disabled',
generateStatsFile: true,
statsOptions: { source: false }
}),
new webpack.DefinePlugin({
'process.env': appConstants()
}),
new webpack.EnvironmentPlugin(['NODE_ENV']),
new MiniCssExtractPlugin({
filename: (process.env.NODE_ENV == "local") ? "[name].css" : "[name].[hash].css",
chunkFilename: (process.env.NODE_ENV == "local") ? "[id].css" : "[id].[hash].css"
}),
new OptimizeCSSAssetsPlugin()
],
devServer: {
historyApiFallback: true,
port: 9090
},
watchOptions: {
aggregateTimeout: 300,
poll: 1000
}
};
// configure source map per-env
if (process.env.NODE_ENV === 'local') {
webpackConfig.devtool = 'eval-source-map';
} else {
webpackConfig.devtool = 'hidden-source-map';
}
module.exports = webpackConfig;
Here is the error I get during build:
ERROR in ./node_modules/bootstrap/dist/css/bootstrap.css 7:0
Module parse failed: Unexpected token (7:0)
You may need an appropriate loader to handle this file type.
| * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
| */
:root {
| --blue: #007bff;
| --indigo: #6610f2;
That error makes me think I'm missing the proper loader but I don't know what other loader I would need for this.
TL;DR
I want to extract all my css files including bootstrap.css into a separate file from my main.js .