I have setup hot reloading with react-hot-loader. In the console it looks like it works, but browser does not actually reload. Why is this?
Ignore the errors, I think they come from a plugin. It correctly detects I change App.jsx but the browser does not update unless I do a full refresh.
My webpack.config.js below:
const path = require("path")
const webpack = require("webpack")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const ExtractTextPlugin = require("extract-text-webpack-plugin")
const context = path.resolve(__dirname, "src")
const {dependencies} = require("./package.json")
module.exports = {
context,
entry: {
vendor: Object.keys(dependencies),
app: [
"react-hot-loader/patch",
"./js/index.js"
]
},
output: {
path: path.resolve(__dirname, "build"),
filename: "[name]-[hash].js"
},
module: {
rules: [
{
test: /\.jsx?$/,
loader: "babel-loader",
exclude: /node_modules/,
options: {
plugins: [
[
"react-css-modules",
{
context
}
]
]
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
loader: "css-loader",
options: {
modules: true,
importLoaders: 1,
localIdentName: "[path]___[name]__[local]___[hash:base64:5]",
sourceMap: true
}
},
'postcss-loader'
]
})
}
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor"
}),
new HtmlWebpackPlugin({
filename: "index.html",
template: "index.html"
}),
new webpack.NamedModulesPlugin(),
new ExtractTextPlugin("css/[name].css")
],
devServer: {
contentBase: path.resolve(__dirname, "src"),
historyApiFallback: true
},
devtool: "eval"
}
index.js
import ReactDOM from "react-dom"
import React from "react"
import {AppContainer} from "react-hot-loader"
import App from "./App.jsx"
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.getElementById("app")
)
}
render(App)
if (module.hot) {
module.hot.accept("./App.jsx", () => render(App))
}
Related
I am using Vue with Webpack (without Vue CLI) and I ran into an issue.
I am building a Design System library, in which I would like to have async chunks so they get small.
When I import as usual the component in the index.ts of the lib
//index.ts
import RedBox from '#/components/RedBox.vue';
export { RedBox };
everything works perfectly.
But when I try to do
const RedBox = () => import('#/components/RedBox.vue');
export { RedBox };
i get
The file is actually there in the bundle.
Here is my webpack config
/* eslint-disable #typescript-eslint/no-var-requires */
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (env) => {
const plugins = [
new VueLoaderPlugin(),
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[name].css',
}),
];
if (env.ANALYZE_BUNDLE) { plugins.push(new BundleAnalyzerPlugin()); }
return {
entry: './src/index.ts',
mode: 'production',
devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'design-system.js',
library: {
name: 'design-system',
type: 'umd',
},
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
},
{
test: /\.ts?$/,
loader: 'ts-loader',
exclude: /node_modules/,
options: {
transpileOnly: true,
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {},
},
'css-loader',
'postcss-loader',
{
loader: 'sass-loader',
options: {},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
},
],
},
plugins,
resolve: {
alias: {
'#': path.resolve(__dirname, 'src'),
},
extensions: [
'.vue',
'.ts',
'.js',
'.css',
'.ttf',
'.otf',
],
},
externals: {
vue: 'Vue',
},
};
};
I'm trying to bundle up all my libraries and for the most part? It works.
However, Vue is not being included in the bundle (but everything else is). I can't figure out how to include Vue with the bundled JS from webpack.
My webpack.config.js looks like this:
const autoprefixer = require("autoprefixer");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebPackPlugin = require("html-webpack-plugin");
var path = require("path");
var Vue = require('vue').default;
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
watch: true,
mode: "production",
entry: "./static/myapp/src/js/index.js",
externals: {
moment: "moment",
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
output: {
filename: "[name].[contenthash].js",
path: path.join(__dirname, "static/myapp/dist/js/"),
publicPath: "/static/myapp/dist/js/",
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
module: {
rules: [
{
test: /\.(scss)|(css)$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: "css-loader", options: { sourceMap: true } },
{
loader: "postcss-loader",
},
"sass-loader",
],
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
},
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: "file-loader",
options: {
name: "[name][hash].[ext]",
outputPath: "fonts/",
},
},
],
},
],
},
plugins: [
new BundleAnalyzerPlugin(),
new MiniCssExtractPlugin({
filename: "../css/[name].[contenthash].css",
}),
new CleanWebpackPlugin(),
new HtmlWebPackPlugin({
template: path.join(
__dirname,
"static/myapp/src/html/webpack_bundles.html"
),
filename: path.join(
__dirname,
"templates/myapp/webpack_bundles.html"
),
inject: false,
}),
],
};
In my index.js I have this:
import "../scss/commonground.scss";
import "../css/style.css";
import "bootstrap";
import "select2";
import "vue";
import "bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css";
import "bootstrap-datepicker/dist/js/bootstrap-datepicker.min";
import "select2/dist/css/select2.css";
All the other libraries (bootstrap, select2, bootstrap-datepicker) get bundled up, the CSS gets bundled together nicely, etc.
The bundle getting created (main.<hash>.js) does not include vuejs. How can I get it to?
I can't figure out how to get it to include vuejs. Any thoughts? Or any ideas that stick out? I've ran through numerous tutorials and how-to's, but can't seem to figure out why this isn't working.
I am setting up a webpack, but I have a problem.
I know that libraries are automatically connected when node_modules is set in modules of resolve.
So I set up the webpack like this(the webpack file is located under the config folder in the root folder.)
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const env = process.env.NODE_ENV;
const isProd = env === "production";
module.exports = {
mode: env,
context: path.resolve(__dirname, '..'),
entry: {
app: './main.js'
},
output: {
filename: !isProd ? `js/[name].js` : 'js/[name].[contenthash:8].js',
path: path.resolve(__dirname, '../dist'),
publicPath: '/',
chunkFilename: !isProd ? `js/[name].js` : 'js/[name].[contenthash:8].js'
},
resolve: {
alias: {
'#': path.resolve(__dirname, '../src'),
vue$: 'vue/dist/vue.runtime.esm-bundler.js'
},
extensions: [
'.mjs',
'.js',
'.jsx',
'.vue',
'.json',
],
modules: [
path.resolve(__dirname, '../src'),
'node_modules',
path.resolve(__dirname, '../node_modules')
],
},
resolveLoader: {
modules: [
'node_modules',
path.resolve(__dirname, '../node_modules')
],
extensions: ['.js', '.json'],
},
module: {
noParse: /^(vue|vue-router|vuex|vuex-router-sync)$/,
rules: [
{
test: /\.vue$/,
use: ['vue-loader']
},
{
test: /\.(png|jpe?g|gif|webp)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 4096,
fallback: {
loader: 'file-loader',
options: {
name: 'img/[name].[hash:8].[ext]',
esModule: false
}
}
}
}
]
},
{
test: /\.(sa|sc|c)ss$/,
use: [ isProd ? {
loader: MiniCssExtractPlugin.loader
} : {
loader: 'style-loader',
}
,
{
loader: "css-loader",
options: {
sourceMap: false,
importLoaders: 2
}
},
{
loader: "sass-loader",
options: {
sourceMap: false
}
}],
},
{
enforce: 'pre',
test: /\.(vue|(j|t)sx?)$/,
exclude: [
/node_modules/,
],
use: [
{
loader: 'eslint-loader',
options: {
extensions: [
'.js',
'.jsx',
'.vue'
],
emitWarning: false,
emitError: false,
fix: true,
}
}
]
},
{
test: /\.m?jsx?$/,
use: [
{loader: 'babel-loader'}
]
}
],
},
plugins: [
new VueLoaderPlugin(),
],
}
However, despite of this setting, code cannot find node_modules.
import Vue from 'vue';
import App from "./src/App.vue";
import { router } from "./src/router/index.js";
new Vue({
router,
render: (h) => h(App),
}).$mount("#root");
this prints out error message on the dev server or at build time.
ERROR in ./main.js
Module not found: Error: Can't resolve 'vue' in '/Users/donghokim/study/wecode/vue-setting-playground/brandi-front-setting'
# ./main.js 1:0-22 5:4-7
However, if set the library path directly, it works.
import Vue from './node_modules/vue/dist/vue';
import App from "./src/App.vue";
import { router } from "./src/router/index.js";
new Vue({
router,
render: (h) => h(App),
}).$mount("#root");
How can I automatically connect node_modules?
solved.... vue$: 'vue/dist/vue.runtime.esm-bundler.js' is of vue 3. I found that vue 2 has no vue.runtime.esm-bundler.js file. After changing to vue.runtime.esm.js, webpack build works
After migrating my CSS files to SCSS, I can see FOUC for my layout elements at the first load (After each reloads of page).
I guess it has something to do with my webpack config so I tried to fix the problem by using mini-css-extract-plugin, but I can still see the problem.
Here is the content of my webpack.config.js file:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const path = require('path');
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production';
module.exports = {
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,{
loader: "css-loader"
}, {
loader: "sass-loader",
}
]
},
{
test: /\.html$/,
use: [
{
loader: "html-loader"
}
]
},
{
test: /(\.(?:le|c)ss)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: false,
},
},
{
loader: 'less-loader',
options: {
sourceMap: false,
javascriptEnabled: true,
},
}
]
},
{
test: /\.(png|jpe?g|gif)$/,
use: [
{
loader: 'file-loader',
},
]
}
]
},
output: {
publicPath: "/"
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
new MiniCssExtractPlugin(),
new MomentLocalesPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.AggressiveMergingPlugin()
],
resolve: {
alias: {
"#ant-design/icons/lib/dist$": path.resolve(__dirname, "./src/icons.js")
}
}
};
The problem wasn't because of Webpack. It was because of me being stupid :)
I imported the CSS file inside of a child component, so when I reload the page, it first shows the layout without any styles and then loads the child component and gives the layout a proper style. So basically, the only thing I did to fix the problem was to import the style in the layout component.
import '../style.scsc'
I had a different thread here: React Build Tool and Dev Server
to setup React with Webpack. Seems like it is working but I have an issue with having the html page show the code from entry point app.js . I can see the code is in bundle.js. If I modify anything in app.js till the render method e.g enter a typo or something I see an error on console but nothing happens with the render() method. Not matter what I do there is no error and nothing shows but a blank page.
app.js
import React from 'react';
import ReactDOM from 'react-dom';
export default class App extends React.Component {
render() {
return (
ReactDOM.render(<h1>Render me!</h1>,
document.getElementById('app'))
);
}
}
Index.html
<!DOCTYPE html>
<html>
<head>
<!-- Bootstrap, latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css">
</head>
<body>
<div id="app"></div>
<script type="text/javascript" src='bundle.js'></script>
</body>
</html>
So if I view page source it just shows just
and not the expected Render me!
And just in case below is my webpack.config
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: {
bundle: './src/app.js'
},
output: {
path: path.join(__dirname, '/dist'),
filename: 'bundle.js'
},
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-1']
}
}]
},
resolve: {
extensions: ['*', '.js', '.jsx']
}
};
Also this is from my package.json. I believe my bundle.js is being served from memory right now.
"scripts": {
"start": "webpack-dev-server --port 3000 --hot --inline",
"build": "webpack --progress --colors"
}
I run npm start to compile and start the server. I was expecting npm build will build to dist folder but it doesn't . For now I just want this working one way or the other so I can start coding.
And .babelrc
{
"presets":[
"es2017", "react"
]
}
You are using WebPack 3.x?
Try this config:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PreloadWebpackPlugin = require('preload-webpack-plugin');
const autoprefixer = require('autoprefixer');
const staticSourcePath = path.join(__dirname, 'static');
const sourcePath = path.join(__dirname);
const buildPath = path.join(__dirname, 'dist');
module.exports = {
devtool: 'source-map',
devServer: {
historyApiFallback: true,
contentBase: './'
},
entry: {
"index" :path.resolve(sourcePath, 'index.js')
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js',
publicPath: '/'
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx'],
modules: [
sourcePath,
path.resolve(__dirname, 'node_modules')
]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development')
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: 'vendor.[chunkhash].js',
minChunks: Infinity
}),
new webpack.LoaderOptionsPlugin({
options: {
postcss: [
autoprefixer({
browsers: [
'last 3 version',
'ie >= 10'
]
})
],
context: staticSourcePath
}
}),
new webpack.HashedModuleIdsPlugin(),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'index.html'),
path: buildPath,
excludeChunks: ['base'],
filename: 'index.html',
minify: {
collapseWhitespace: true,
collapseInlineTagWhitespace: true,
removeComments: true,
removeRedundantAttributes: true
}
}),
new PreloadWebpackPlugin({
rel: 'preload',
as: 'script',
include: 'all',
fileBlacklist: [/\.(css|map)$/, /base?.+/]
}),
new webpack.NoEmitOnErrorsPlugin()
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
}
},
include: sourcePath
},
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { minimize: true } },
'postcss-loader',
'sass-loader'
]
})
},
{
test: /\.(eot?.+|svg?.+|ttf?.+|otf?.+|woff?.+|woff2?.+)$/,
use: 'file-loader?name=assets/[name]-[hash].[ext]'
},
{
test: /\.(png|gif|jpg|svg)$/,
use: [
'url-loader?limit=20480&name=assets/[name]-[hash].[ext]'
],
include: staticSourcePath
}
]
}
};