I have a custom build setup for chrome extension which injects iframe to webpages, and this iframe is built using vue.js.
Entry point for building this iframe is src/popup/js and it should output to dist/popup.
This all works fine, but I don't know how to setup hot reload so I can see the changes in browser the moment I make changes in code.
Currently, when I run build step, everything is prepared and placed into dist folder, and iframe I want to hot reload is dist/popup/popup.html file.
This is my package.json:
{
"name": "extensionname",
"version": "1.0.17",
"description": "Chrome Extension",
"scripts": {
"lint": "eslint --ext .js,.vue src",
"prettier": "prettier \"src/**/*.{js,vue}\"",
"prettier:write": "npm run prettier -- --write",
"build-zip": "node scripts/build-zip.js",
"build:prod": "cross-env NODE_ENV=production TARGET_ENV=production webpack --hide-modules && cross-env NODE_ENV=production TARGET_ENV=production npm run build-zip",
"build:store": "cross-env NODE_ENV=production TARGET_ENV=store webpack --hide-modules && cross-env NODE_ENV=production TARGET_ENV=store npm run build-zip",
"build:dev": "cross-env NODE_ENV=development TARGET_ENV=development webpack --hide-modules && cross-env NODE_ENV=development TARGET_ENV=development npm run build-zip",
"build:test": "cross-env NODE_ENV=development TARGET_ENV=test webpack --hide-modules && cross-env NODE_ENV=development TARGET_ENV=test npm run build-zip"
},
"dependencies": {
"axios": "^0.18.0",
"emoji-mart-vue": "^2.6.6",
"moment": "^2.22.2",
"vue": "^2.6.10",
"vuetify": "^1.5.4",
"vuex": "^3.0.1",
"split-sms": "^0.1.7"
},
"devDependencies": {
"#babel/core": "^7.1.2",
"#babel/plugin-proposal-optional-chaining": "^7.0.0",
"#babel/preset-env": "^7.1.0",
"#types/chrome": "^0.0.74",
"archiver": "^3.0.0",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.2",
"copy-webpack-plugin": "^4.5.3",
"core-js": "^2.6.5",
"cross-env": "^5.2.0",
"css-loader": "^0.28.11",
"ejs": "^2.6.1",
"eslint": "^5.16.0",
"eslint-config-prettier": "^3.1.0",
"eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^2.1.2",
"eslint-plugin-import": "^2.16.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-prettier": "^3.0.1",
"eslint-plugin-promise": "^4.1.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.2",
"file-loader": "^1.1.11",
"mini-css-extract-plugin": "^0.4.4",
"node-sass": "^4.9.3",
"prettier": "^1.14.3",
"sass-loader": "^7.1.0",
"vue-loader": "^15.4.2",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2"
}
}
This is webpack.config.js :
const webpack = require('webpack');
const ejs = require('ejs');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const { version } = require('./package.json');
const config = {
mode: process.env.NODE_ENV,
context: __dirname + '/src',
entry: {
'popup/popup': './popup/popup.js',
},
output: {
path: __dirname + '/dist',
filename: '[name].js',
},
resolve: {
extensions: ['.js', '.vue', '.json'],
},
module: {
rules: [
{
test: /\.vue$/,
loaders: 'vue-loader',
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.scss$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'],
},
{
test: /\.sass$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader?indentedSyntax'],
},
{
test: /\.(png|jpg|gif|svg|ico)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?emitFile=false',
},
},
],
},
plugins: [
new webpack.DefinePlugin({
global: 'window',
'process.env.TARGET_ENV': JSON.stringify(process.env.TARGET_ENV)
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
}),
new CopyWebpackPlugin([
{ from: 'images', to: 'images' },
{ from: 'scripts', to: 'scripts' },
{ from: 'css', to: 'css'},
{ from: 'popup/popup.html', to: 'popup/popup.html', transform: transformHtml },
{
from: 'manifest.json',
to: 'manifest.json',
transform: content => {
const jsonContent = JSON.parse(content);
jsonContent.version = version;
if (process.env.TARGET_ENV != 'store') {
jsonContent['content_security_policy'] = "script-src 'self' 'unsafe-eval'; object-src 'self'";
jsonContent['key'] = '123456';
}
return JSON.stringify(jsonContent, null, 4);
},
},
{
from: 'config.json',
to: 'config.js',
transform: content => {
return transformConfigForExtension(content);
},
},
]),
],
};
if (config.mode === 'production') {
config.plugins = (config.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"',
},
}),
]);
}
function transformHtml(content) {
return ejs.render(content.toString(), {
...process.env,
});
}
function transformConfigForExtension(content){
let extensionConfig = JSON.parse(content.toString())[process.env.TARGET_ENV];
return 'const config = ' + JSON.stringify(extensionConfig, null, 4);
}
module.exports = config;
And this is my project structure:
To the best of my knowledge, this is not possible on Chrome. Take a look at web-ext. It allows you to hot-reload code while developing an extension on Firefox.
Alternatively, you can also create your own extension that takes advantage of the management API to reload an extension. I'm guessing this is what web-ext does in the background.
Related
I am using Webpack 5 to build a static HTML boilerplate. Everything works fine, Webpack is compiled successfully and browser is updated whenever I make change to HTML, SCSS/CSS or JS file in my source code.
The problem happens if there is error in the code, WDS will stop working and browser will display an error message in the console, for example:
Even after I fix the error and Webpack says that it is compiled successfully, WDS still does not work and the browser keeps stuck at the error. I have to reload the browser manually to make it work again.
Can anyone please help me? What should I do to make browser updated again after error is fixed?
I found the same question webpack-dev-server stops compiling after a syntax error, requires restart, but there is no proper answer to it so I have to ask another one.
This is my webpack.common.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const fs = require('fs');
// Prepare plugins
const plugins = [
new MiniCssExtractPlugin({
filename: './style/main.css?v=[contenthash]',
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
inject: 'body',
filename: 'index.html',
minify: {
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
];
// Create more HtmlWebpackPlugin
const files = fs.readdirSync(path.resolve('.', 'src/pages'), 'utf8');
files.forEach((file) => {
const page = new HtmlWebpackPlugin({
template: `src/pages/${file}`,
inject: 'body',
filename: `pages/${file}`,
minify: {
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
});
plugins.push(page);
});
module.exports = {
entry: './src/scripts/index.js',
output: {
path: path.resolve('.', 'build'),
filename: './js/bundle.js?v=[contenthash]',
},
module: {
rules: [
{
test: /\.js$/,
use: ['babel-loader'],
exclude: [/node_modules/],
},
{
test: /\.(s?css)$/,
use: [
MiniCssExtractPlugin.loader,
'css-hot-loader',
'css-loader',
'sass-loader',
'import-glob-loader',
{
loader: 'postcss-loader',
options: {
sourceMap: true,
postcssOptions: {
plugins: () => [require('autoprefixer')],
},
},
},
],
},
{
test: /\.(gif|png|jpe?g|svg|woff|eot|ttf|woff2)$/,
// use: 'url-loader',
type: 'asset/resource',
},
{
test: /\.html$/i,
loader: 'html-loader', // export HTML as string. HTML is minimized when the compiler demands.
options: {
sources: false,
},
},
],
},
plugins,
};
This is my webpack.dev.js:
const path = require('path');
const { merge } = require('webpack-merge');
const WebpackNotifierPlugin = require('webpack-notifier');
const ESLintPlugin = require('eslint-webpack-plugin');
const StylelintPlugin = require('stylelint-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: path.resolve('.', 'src'), // source of static assets
port: 1802, // port to run dev-server
hot: true, // hot reload
watchContentBase: true,
// open: true, // immediately open browser to show localhost:1802 when start script
},
plugins: [
new ESLintPlugin({}),
new StylelintPlugin({ fix: true }),
new WebpackNotifierPlugin({ onlyOnError: true }),
],
});
This is my package.json
{
"name": "static-web-boilerplate",
"version": "1.0.0",
"description": "Simple boilerplate for developing static web projects",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "cross-env ENV=development webpack serve --config webpack/webpack.dev.js --progress",
"start:prod": "npm run build && serve build",
"build": "cross-env ENV=production webpack --config webpack/webpack.prod.js --progress --stats-error-details"
},
"author": "Hau Pham",
"license": "ISC",
"dependencies": {
"#babel/runtime": "^7.14.6",
"autoprefixer": "^10.2.6",
"clean-webpack-plugin": "^4.0.0-alpha.0",
"copy-webpack-plugin": "^9.0.1",
"css-minimizer-webpack-plugin": "^3.0.2",
"eslint-webpack-plugin": "^2.5.4",
"html-webpack-plugin": "^5.3.2",
"mini-css-extract-plugin": "^1.6.1",
"serve": "^12.0.0",
"stylelint-webpack-plugin": "^2.2.2",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack-merge": "^5.8.0",
"webpack-notifier": "^1.13.0"
},
"devDependencies": {
"#babel/core": "^7.14.6",
"#babel/plugin-transform-runtime": "^7.14.5",
"#babel/preset-env": "^7.14.7",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"cross-env": "^7.0.3",
"css-hot-loader": "^1.4.4",
"css-loader": "^5.2.6",
"eslint": "^7.29.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-config-prettier": "^8.3.0",
"eslint-config-stylelint": "^13.1.1",
"eslint-import-resolver-webpack": "^0.13.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.1.2",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.4.0",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"import-glob-loader": "^1.1.0",
"node-sass": "^6.0.1",
"postcss-loader": "^6.1.0",
"prettier": "^2.3.2",
"sass-loader": "^12.1.0",
"stylelint": "^13.13.1",
"stylelint-config-prettier": "^8.0.2",
"stylelint-config-recommended": "^5.0.0",
"stylelint-config-standard": "^22.0.0",
"stylelint-config-standard-scss": "^1.1.0",
"stylelint-scss": "^3.19.0",
"terser-webpack-plugin": "^5.1.4",
"url-loader": "^4.1.1",
"webpack": "^5.41.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
}
}
After many hours of research, I have found the solution. According to comment on webpack-dev-server github page, updating webpack-dev-server to version 4 should fix this. I tried and it did fix the issue!
(At the time of this answer, the newest version 4 is 4.0.0-beta.3)
My project environment is , React with redux and redux-saga , webpack
Jenkins is used for CI/CD
since a month , we are getting a strange issue, the Jenkins (webpack) build & deployment is successful however when I access the portal it shows a blank page because of below Javascript error
Uncaught ReferenceError: saga is not defined
at Module.1148 (main.44c97d10353333934fe5.bundle.js:1)
at __webpack_require__ (manifest.6a34ff8be70a737e5aa6.bundle.js:1)
at Object.646 (main.44c97d10353333934fe5.bundle.js:1)
at __webpack_require__ (manifest.6a34ff8be70a737e5aa6.bundle.js:1)
at checkDeferredModules (manifest.6a34ff8be70a737e5aa6.bundle.js:1)
at Array.webpackJsonpCallback [as push] (manifest.6a34ff8be70a737e5aa6.bundle.js:1)
at vendor.fef8d73f71dc764a97a1.bundle.js:1
when looked at the failing file in code base the sagas.js file has "export default sagas" , so the s in sagas is truncated during build process hence the javascript error
After re-running the same build in Jenkins then it is producing a clean build and application works normally without above error
and strangely this behaviour doesn't occur on every build it is intermittent
another error similar to this is
built version of utag.js with errors
actual version of utag.js from code base
The main issue is I couldn't replicate the issue locally , I have run the webpack build on the branch which resulted in javascript error - but no luck , everytime webpack produced a clean build locally
Here are my config files
Package.json
{
"name": "portal",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "webpack-dev-server --open --inline --progress --env development --config webpack/dev.config.js",
"build:prod": "webpack --env production --config webpack/prod.config.js",
"build:test": "webpack --env test --config webpack/prod.config.js",
"stylelint": "stylelint '**/*.scss', '**/*.css'",
"stylelint:silentexit": "stylelint '**/*.scss', '**/*.css'; exit 0",
"jslint": "eslint . --fix",
"jslint:silentexit": "eslint .; exit 0",
"test": "npm run jslint && npm run test:unit",
"test:unit": "jest --colors",
"test:watch": "jest --watch --passWithNoTests",
"test:coverage": "jest --coverage -u --colors",
"storybook": "start-storybook -p 9001 -c .storybook",
"generateSvgIconComponents": "styled-svg src/icons/*.svg --size=small:18x18 --size=medium:24x24 --size=large:36x36"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 10",
"not op_mini all"
],
"dependencies": {
"#babel/polyfill": "^7.4.4",
"#rebass/components": "^4.0.0-1",
"acorn": "^6.2.0",
"babel-plugin-react-css-modules": "^5.2.6",
"babel-polyfill": "^6.26.0",
"bootstrap": "^4.1.3",
"connected-react-router": "^6.5.2",
"fixed-data-table-2": "^0.8.26",
"glamor": "^2.20.40",
"history": "^4.9.0",
"html-webpack-plugin": "^3.2.0",
"javascript-excel": "^1.0.3",
"jspdf": "^1.5.3",
"jspdf-react": "^1.0.10",
"lodash": "^4.17.14",
"moment": "^2.24.0",
"prop-types": "^15.7.2",
"qs": "^6.6.0",
"react": "^16.8.2",
"react-bootstrap": "^0.32.4",
"react-compound-slider": "^2.3.0",
"react-csv": "^1.1.1",
"react-data-export": "^0.5.0",
"react-draggable": "^4.0.3",
"react-list-drag-and-drop": "^0.9.1",
"react-markdown": "^4.2.2",
"react-pdf": "^4.1.0",
"react-redux": "^6.0.1",
"react-router-dom": "^5.0.1",
"react-tooltip": "^3.10.0",
"react-virtualized": "^9.21.1",
"redux": "^4.0.1",
"redux-actions": "^2.6.4",
"redux-saga": "^1.1.3",
"reselect": "^4.0.0",
"styled-components": "^4.3.1",
"styled-system": "^4.2.4",
"validate.js": "^0.13.1",
"webpack-merge": "^4.2.2",
"whatwg-fetch": "^3.0.0",
"xlsx": "^0.14.3"
},
"devDependencies": {
"#babel/core": "^7.4.5",
"#babel/plugin-proposal-class-properties": "^7.4.4",
"#babel/plugin-transform-react-jsx-source": "^7.5.0",
"#babel/preset-env": "^7.4.5",
"#babel/preset-react": "^7.0.0",
"#storybook/react": "^4.1.18",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.8.0",
"babel-loader": "^8.0.6",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-root-import": "^6.2.0",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-plugin-transform-runtime": "^6.23.0",
"clean-webpack-plugin": "^2.0.2",
"copy-webpack-plugin": "^5.0.4",
"css-loader": "^2.1.1",
"deep-freeze": "0.0.1",
"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",
"eslint": "^5.14.1",
"eslint-loader": "^2.1.2",
"eslint-plugin-react": "^7.13.0",
"faker": "^4.1.0",
"html-loader": "^0.5.5",
"jest": "^24.8.0",
"jest-enzyme": "^7.0.1",
"jest-react-hooks-mock": "^1.1.0",
"node-fetch": "^2.6.0",
"pdf2json": "^1.1.8",
"react-dom": "^16.7.0",
"redux-mock-store": "^1.5.3",
"redux-saga-testing": "^1.0.5",
"sinon": "^7.3.2",
"style-loader": "^0.23.1",
"styled-svg": "^2.4.7",
"stylelint": "^9.10.1",
"stylelint-config-standard": "^18.3.0",
"svg-url-loader": "^3.0.0",
"uglifyjs-webpack-plugin": "^2.1.3",
"webpack": "4.41.2",
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.4",
"webpack-dev-server": "^3.7.1"
}
}
webpack/base.config.js
'use strict'
const path = require('path')
const CleanWebpackPlugin = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
const dirName = __dirname.replace('webpack','');
const util = require('./util');
// cleans 'dist' folder everytime before a new build
const cleanPLugin = env => (new CleanWebpackPlugin({
root: path.join(dirName, util.getRootContext(env) ),
verbose: true,
dry: false
}));
const AnalyzerPlugin = new BundleAnalyzerPlugin(
{
analyzerMode: 'none'
}
);
const copyWebpackPlugin = env => ( new CopyPlugin([ {
from : path.join(dirName, 'src/assets/static'),
to : path.join(dirName, `dist/${util.getRootContext(env)}/assets`)
}, {
from : path.join(dirName, 'src/assets/pages'),
to : path.join(dirName, `dist/${util.getRootContext(env)}`)
}
]));
const HTMLPlugin = new HtmlWebpackPlugin({
template: path.join(dirName, 'src/scripts/index.html'),
chunksSortMode: 'none'
});
module.exports = (env) => {
// BUILDING WEBPACK
const config = {};
config.plugins = [cleanPLugin(env), AnalyzerPlugin, HTMLPlugin, copyWebpackPlugin(env)]
config.entry = ["whatwg-fetch", "babel-polyfill", path.join(dirName, '/src/scripts/index.js')]
config.output = {
path: path.join(dirName, '/dist'),
filename: '[name].build.js',
chunkFilename: '[name].bundle.js',
}
config.module = {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.(png|jpg|gif|woff|ttf|woff2)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {}
}
},
{
test: /\.(css|less)$/,
use: [ 'style-loader', 'css-loader' ]
}
]
}
config.resolve = {
extensions: [ '.js', '.jsx', '.json', '.css' ],
alias: {
DesignSystem: path.resolve(dirName, 'src/design-system/'),
Icons: path.resolve(dirName, 'src/icons/'),
Scripts: path.resolve(dirName, 'src/scripts/'),
CMS: path.resolve(dirName, 'cms/'),
}
}
config.node = { fs: 'empty' }
return config
}
webpack/prod.config.js
const merge = require('webpack-merge');
const baseConfig = require('./base.config.js');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const path = require('path');
const util = require('./util');
const dirName = __dirname.replace('webpack','');
module.exports = env => (merge(baseConfig(env),
{
optimization: {
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: 'vendor',
chunks: 'initial'
}
}
},
runtimeChunk: {
name: 'manifest'
},
minimizer: [
new UglifyJsPlugin({
sourceMap: true,
uglifyOptions: {
ecma: 8,
mangle: false,
keep_classnames: true,
keep_fnames: true
}
})
]
},
output: {
path: path.join(dirName, `./dist/${util.getRootContext(env)}`),
publicPath: `/${util.getRootContext(env)}/`,
chunkFilename: '[name].[chunkhash].bundle.js',
filename: '[name].[chunkhash].bundle.js'
},
mode: 'production'
}
));
npm run build:prod is the command which runs this build
Any tips or help would be greatly appreciated.
Thanks!!
I want to use webpack so that it will automatically compile any and all .scss files in my /src/app folder into a single .css file without me having to explicity point to all of the .scss files / import them.
I am trying to use ExtractTextPlugin to do this but it does not seem to be working. Do I need to provide a more specific entry point? Are my loaders not configured correctly? Or is there something else wrong? Thanks!
webpack.config.js:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const DIST_DIR = path.resolve(__dirname, "dist");
const SRC_DIR = path.resolve(__dirname, "src");
const config = {
devtool: 'inline-source-map',
entry: [
"babel-polyfill",
SRC_DIR + "/app/index.js"
SRC_DIR + "/app/"
],
target: 'web',
output: {
path: DIST_DIR + "/app/",
filename: "bundle.js",
publicPath: "/app/"
},
devServer: {
contentBase: './dist',
historyApiFallback: true,
hot: true,
proxy: {
'/api': {
target: 'http://localhost:5001',
secure: false,
},
}
},
plugins: [
new ExtractTextPlugin({filename: "foo.css", allChunks: true})
],
module: {
rules: [
{
enforce: "pre",
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
options: {
failOnWarning: false,
failOnError: true
}
},
{
test: /\.js$/,
include: SRC_DIR,
loader: 'babel-loader',
query: {
presets: ['react', 'stage-2']
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: 'css-loader?importLoaders=1',
})
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract(['css-loader', 'sass-loader']),
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loaders: ['file-loader?context=src/images&name=images/[path][name].[ext]', {
loader: 'image-webpack-loader',
query: {
mozjpeg: {
progressive: true,
},
gifsicle: {
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
pngquant: {
quality: '75-90',
speed: 3,
},
},
}],
exclude: path.resolve(__dirname, "node_modules"),
include: __dirname,
},
{
test: /\.woff2?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
// loader: "url?limit=10000"
use: "url-loader"
},
{
test: /\.(ttf|eot|svg)(\?[\s\S]+)?$/,
use: 'file-loader'
},
]
},
};
module.exports = config;
package.json
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "jest",
"watch": "webpack --progress --watch",
"start": "yarn build",
"build": "webpack -d && cp src/index.html dist/index.html && webpack-dev-server --inline --hot --history-api-fallback",
"build:dev": "webpack && cp src/index.html dist/index.html",
"build:prod": "webpack -p && cp src/index.html dist/index.html"
},
"author": "",
"license": "UNLICENSED",
"devDependencies": {
"babel-cli": "7.0.0-beta.3",
"babel-eslint": "7",
"babel-loader": "^7.1.2",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.6.0",
"babel-preset-react": "^6.24.1",
"babel-preset-stage-2": "^6.24.1",
"css-loader": "^0.28.7",
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"eslint": "3.x",
"eslint-config-airbnb": "^15.1.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-import": "^2.7.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
"eslint-plugin-react": "^7.4.0",
"extract-text-webpack-plugin": "^3.0.0",
"fetch-mock": "^6.0.0-beta.7",
"file-loader": "^0.11.2",
"image-webpack-loader": "^3.4.2",
"jest": "^23.1.0",
"jest-enzyme": "^4.0.0",
"jest-fetch-mock": "^1.6.4",
"node-sass": "^4.9.0",
"redux-mock-store": "^1.5.3",
"sass-loader": "^6.0.6",
"url-loader": "^0.5.9",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
},
"dependencies": {
"#trendmicro/react-toggle-switch": "^0.5.7",
"babel-polyfill": "^6.26.0",
"cross-fetch": "^1.1.1",
"font-awesome": "^4.7.0",
"highcharts": "^6.0.4",
"history": "^4.7.2",
"js-cookie": "^2.2.0",
"less-loader": "^4.0.5",
"libphonenumber-js": "^0.4.42",
"lodash": "^4.17.4",
"moment": "^2.19.1",
"prop-types": "^15.6.0",
"query-string": "^5.0.1",
"rc-time-picker": "^3.1.0",
"react": "^16.0.0",
"react-animations": "^1.0.0",
"react-autosuggest": "^9.3.4",
"react-circular-progressbar": "^0.8.0",
"react-datepicker": "^0.59.0",
"react-dom": "^16.0.0",
"react-highcharts": "^15.0.0",
"react-list": "^0.8.8",
"react-redux": "^5.0.6",
"react-router": "^4.2.0",
"react-router-dom": "^4.2.2",
"react-router-redux": "^5.0.0-alpha.6",
"react-select": "^1.0.0-rc.10",
"react-transition-group": "^1.2.0",
"redux": "^3.7.2",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"styled-components": "3.2.3",
"twilio-client": "^1.4.33"
},
"jest": {
"setupTestFrameworkScriptFile": "./node_modules/jest-enzyme/lib/index.js"
}
}
without me having to explicity point to all of the .scss files /
import them.
You can't do that, webpack is not like gulp or other task runner that you can just point patterns and it will apply transformations to them.
Webpack works with dependency graphs, and these graphs are going to start from your entry points. On each entrypoint it reads the dependencies and apply those loaders specified for each file extension. Webpack only knows the existence of that file, if it is imported in any file that is part of the dependency graph.
If you want to transform css the way that you described, i suggest you moving towards a more task runner library such as gulp.
I am using the MERN stack. I had to use a 3rd party html admin template which has a lot of standard js and css files (jquery, bootstrap, datatables etc.). To integrate it with react, I created a "public" folder in the root directory of my project. I then configured Express to serve this folder as a static folder and placed the required css and html files inside this folder. To use them, I added the css in the head section of the index.html file and the js in the end of the body. It works when I run the server in development mode and there are no issues. When I run it in production mode, somehow the layout gets messed up. If I refresh it with CTRL + F5 it gets fixed but when I navigate to a new page it gets ruined again and I have to CTRL + F5 it again to display properly.
This is my webpack.config.dev.js
var webpack = require('webpack');
var cssnext = require('postcss-cssnext');
var postcssFocus = require('postcss-focus');
var postcssReporter = require('postcss-reporter');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: {
app: [
'eventsource-polyfill',
'webpack-hot-middleware/client',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
'./client/index.js',
],
vendor: [
'react',
'react-dom',
],
},
output: {
path: __dirname,
filename: 'app.js',
publicPath: 'http://0.0.0.0:8000/',
},
resolve: {
extensions: ['', '.js', '.jsx'],
modules: [
'client',
'node_modules',
],
},
module: {
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',
}, {
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader'],
}, {
test: /\.jsx*$/,
exclude: [/node_modules/, /.+\.config.js/],
loader: 'babel',
}, {
test: /\.(jpe?g|gif|png|svg)$/i,
loader: 'url-loader?limit=10000',
}, {
test: /\.json$/,
loader: 'json-loader',
},
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.js',
}),
new webpack.DefinePlugin({
'process.env': {
CLIENT: JSON.stringify(true),
'NODE_ENV': JSON.stringify('development'),
}
}),
],
postcss: () => [
postcssFocus(),
cssnext({
browsers: ['last 2 versions', 'IE > 10'],
}),
postcssReporter({
clearMessages: true,
}),
],
};
This is my webpack.config.prod.js
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var ManifestPlugin = require('webpack-manifest-plugin');
var ChunkManifestPlugin = require('chunk-manifest-webpack-plugin');
var cssnext = require('postcss-cssnext');
var postcssFocus = require('postcss-focus');
var postcssReporter = require('postcss-reporter');
var cssnano = require('cssnano');
module.exports = {
devtool: 'hidden-source-map',
entry: {
app: [
'./client/index.js',
],
vendor: [
'react',
'react-dom',
]
},
output: {
path: __dirname + '/dist/client/',
filename: '[name].[chunkhash].js',
publicPath: '/',
},
resolve: {
extensions: ['', '.js', '.jsx'],
modules: [
'client',
'node_modules',
],
},
module: {
loaders: [
{
test: /\.css$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?localIdentName=[hash:base64]&modules&importLoaders=1!postcss-loader'),
}, {
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader'],
}, {
test: /\.jsx*$/,
exclude: /node_modules/,
loader: 'babel',
}, {
test: /\.(jpe?g|gif|png|svg)$/i,
loader: 'url-loader?limit=10000',
}, {
test: /\.json$/,
loader: 'json-loader',
},
],
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.js',
}),
new ExtractTextPlugin('app.[chunkhash].css', { allChunks: true }),
new ManifestPlugin({
basePath: '/',
}),
new ChunkManifestPlugin({
filename: "chunk-manifest.json",
manifestVariable: "webpackManifest",
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false,
}
}),
],
postcss: () => [
postcssFocus(),
cssnext({
browsers: ['last 2 versions', 'IE > 10'],
}),
cssnano({
autoprefixer: false
}),
postcssReporter({
clearMessages: true,
}),
],
};
Package.json
{
"name": "",
"version": "2.0.0",
"description": "",
"scripts": {
"test": "cross-env NODE_ENV=test PORT=8080 MONGO_URL=mongodb://localhost:27017/mern-test node_modules/.bin/nyc node --harmony-proxies node_modules/.bin/ava",
"watch:test": "npm run test -- --watch",
"cover": "nyc npm run test",
"check-coverage": "nyc check-coverage --statements 100 --branches 100 --functions 100 --lines 100",
"start": "cross-env BABEL_DISABLE_CACHE=1 NODE_ENV=development nodemon index.js",
"start:prod": "cross-env NODE_ENV=production node index.js",
"bs": "npm run clean && npm run build && npm run build:server && npm run start:prod",
"build": "cross-env NODE_ENV=production webpack --config webpack.config.prod.js",
"build:server": "cross-env NODE_ENV=production webpack --config webpack.config.server.js",
"clean": "rimraf dist",
"slate": "rimraf node_modules && npm install",
"lint": "eslint client server"
},
"pre-commit": [
"lint",
"test"
],
"repository": {
"type": "git",
"url": "git+https://github.com/Hashnode/mern-starter.git"
},
"bugs": {
"url": "https://github.com/Hashnode/mern-starter/issues"
},
"homepage": "https://github.com/Hashnode/mern-starter#readme",
"author": "Prashant Abhishek <prashant.abhishek7g#gmail.com>, Mayank Chandola <imayankchd#gmail.com>, Sandeep Panda <sandeep#hashnode.com>, Syed Fazle Rahman <fazle#hashnode.com>, Alkshendra Maurya <alkshendra#hashnode.com>",
"license": "MIT",
"dependencies": {
"babel-core": "^6.9.1",
"bcrypt-nodejs": "0.0.3",
"body-parser": "^1.15.1",
"compression": "^1.6.2",
"cross-env": "^1.0.8",
"cuid": "^1.3.8",
"express": "^4.13.4",
"intl": "^1.2.4",
"intl-locales-supported": "^1.0.0",
"isomorphic-fetch": "^2.2.1",
"jsonwebtoken": "^8.2.1",
"limax": "^1.3.0",
"mongoose": "^4.4.20",
"morgan": "^1.9.0",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"react": "^15.1.0",
"react-contexify": "^3.0.0",
"react-dom": "^15.1.0",
"react-helmet": "^3.1.0",
"react-intl": "^2.1.2",
"react-notify-toast": "^0.4.0",
"react-redux": "^4.4.5",
"react-router": "^2.4.1",
"react-router-dom": "^4.2.2",
"react-toastify": "^4.0.1",
"redux": "^3.5.2",
"redux-thunk": "^2.1.0",
"sanitize-html": "^1.11.4"
},
"devDependencies": {
"ava": "^0.15.2",
"babel-eslint": "^6.0.4",
"babel-loader": "^6.2.4",
"babel-plugin-webpack-loaders": "^0.7.0",
"babel-polyfill": "^6.9.1",
"babel-preset-es2015": "^6.9.0",
"babel-preset-es2015-native-modules": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babel-preset-react-optimize": "^1.0.1",
"babel-preset-stage-0": "^6.5.0",
"babel-register": "^6.9.0",
"chai": "^3.5.0",
"chunk-manifest-webpack-plugin": "0.1.0",
"coveralls": "^2.11.9",
"css-loader": "^0.23.1",
"css-modules-require-hook": "^4.0.1",
"cssnano": "^3.7.0",
"enzyme": "^2.3.0",
"eslint": "^2.11.1",
"eslint-config-airbnb": "^9.0.1",
"eslint-plugin-ava": "^2.4.0",
"eslint-plugin-import": "^1.8.1",
"eslint-plugin-jsx-a11y": "^1.3.0",
"eslint-plugin-react": "^5.1.1",
"eventsource-polyfill": "^0.9.6",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5",
"jsdom": "^9.2.1",
"json-loader": "^0.5.4",
"mock-css-modules": "^1.0.0",
"mockgoose": "^6.0.3",
"nock": "^8.0.0",
"nodemon": "^1.9.2",
"null-loader": "^0.1.1",
"nyc": "^6.4.4",
"postcss-cssnext": "^2.6.0",
"postcss-focus": "^1.0.0",
"postcss-loader": "^0.9.1",
"postcss-reporter": "^1.3.3",
"pre-commit": "^1.1.3",
"react-addons-test-utils": "^15.1.0",
"react-hot-loader": "^3.0.0-beta.2",
"redux-ava": "^2.0.0",
"redux-devtools": "^3.3.1",
"redux-devtools-dock-monitor": "^1.1.1",
"redux-devtools-log-monitor": "^1.0.11",
"rimraf": "^2.5.2",
"script-loader": "^0.7.2",
"sinon": "^1.17.4",
"style-loader": "^0.13.1",
"supertest": "^1.2.0",
"url-loader": "^0.5.7",
"webpack": "2.1.0-beta.8",
"webpack-dev-middleware": "^1.6.1",
"webpack-dev-server": "^2.1.0-beta.0",
"webpack-externals-plugin": "^1.0.0",
"webpack-hot-middleware": "^2.10.0",
"webpack-manifest-plugin": "^1.0.1"
},
"engines": {
"node": ">=4"
},
"ava": {
"files": [
"client/**/*.spec.js",
"server/**/*.spec.js"
],
"source": [
"client/**/*.js",
"server/**/*.js"
],
"failFast": true,
"babel": "inherit",
"require": [
"./server/util/setup-test-env.js"
]
},
"nyc": {
"include": [
"client/**/*.js",
"server/**/*.js"
],
"exclude": [
"**/*.spec.js",
"client/reducers.js",
"client/store.js",
"client/routes.js",
"server/util/setup-test-env.js",
"server/util/test-helpers.js",
"server/config.js",
"server/dummyData.js"
],
"reporter": [
"lcov",
"text",
"html"
]
}
}
Can this be fixed?
EDIT: It seems that the page sometimes loads correctly even without CTRL + F5 refresh. My gut tells me the issue lies with the order that the JS files are loaded. Any tips on how to keep the loading order the same in dev and prod?
In case of webpack.config.prod.js If you see this part of code
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?localIdentName=[hash:base64]&modules&importLoaders=1!postcss-loader'), 42. loader: 'style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader',}
Just remove ExtractTextPlugin.extract and modify this part of code to
'style-loader!css-loader?localIdentName=[name]__[local]__[hash:base64:5]&modules&importLoaders=1&sourceMap!postcss-loader'
I've created a MERN (MongoDB, ExpressJS, React, Node) project via express-generator (express myNewApp).
Inside a react component I have this piece of ES6 code
onChange = (event, { newValue }) => { // FYI this is line 53
this.setState({
value: newValue
});
};
When I run npm start I get this error: Module build failed: SyntaxError: Unexpected token (53:13).
Here's my package.json:{
"name": "myNewApp",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "webpack --progress --colors --watch -d",
"build": "webpack --progress --colors -p"
},
"dependencies": {
"axios": "^0.15.3",
"babel-cli": "^6.11.4",
"babel-core": "^6.13.2",
"babel-preset-es2015": "^6.13.2",
"babel-preset-react": "^6.11.1",
"body-parser": "~1.16.0",
"cookie-parser": "~1.4.3",
"debug": "~2.6.0",
"ejs": "^2.5.6",
"express": "~4.14.1",
"jade": "~1.11.0",
"mongojs": "^2.4.0",
"morgan": "~1.7.0",
"react": "^15.4.2",
"react-autosuggest": "^9.3.2",
"react-bootstrap": "^0.30.7",
"react-dom": "^15.4.2",
"react-router": "^2.6.1",
"serve-favicon": "~2.3.2"
},
"devDependencies": {
"babel-loader": "^6.2.10",
"http-server": "^0.9.0",
"webpack": "^1.13.3"
}
}
My webpack config file looks like this.
var webpack = require('webpack');
var definePlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true')),
__PRERELEASE__: JSON.stringify(JSON.parse(process.env.BUILD_PRERELEASE || 'false'))
});
var commonsPlugin = new webpack.optimize.CommonsChunkPlugin('common.js');
module.exports = {
cache: true,
entry: { main: './views/index.jsx' },
output: { path: 'public/build', filename: '[name].js' },
module: {
loaders: [
{test: /\.jsx?$/, loader: 'babel', exclude: /(node_modules|bower_components)/, query: { presets: ['react', 'es2015'] }},
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
plugins: [
definePlugin,
commonsPlugin
]
};
npm i --save-dev babel-preset-stage-0
Change webpack.config.js: query: { presets: ['react', 'es2015', 'stage-0']
onChange = ... is a class property assignment, in order for your code to transpile using Babel, you need to npm install --save-dev babel-plugin-transform-class-properties, and then to invoke the plugin inside your .babelrc file, see here for full details.