why split app and vendor js code fails in webpack & react - reactjs

My app.js requires react.
I am following the following instructions to split the app and react code: https://webpack.github.io/docs/code-splitting.html#split-app-and-vendor-code.
Unfortunately, webpack generate app.bundle.js and vendors.bundle.js; both contains react.js library, which is not desired.
I am expecting webpack to generate a small app.bundle.js(which does not contains react) and a large vendor.js(which contains react), according to the link post above.
My webpack configure file:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: {
app: "./app.js",
vendors: ['react']
},
output: {
filename: '[name].bundle.js' // Notice we use a variable
},
plugin: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendors", /* filename= */"vendor.js")
],
module: {
preLoaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'source-map'
}
],
loaders: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loaders: [
'react-hot',
'babel?presets[]=stage-0,presets[]=react,presets[]=es2015'
]
}
]
}
};
My app.js file:
// Import React and JS
var React = require('react')
React.render(
React.createElement('h1', null, 'Hello, world!'),
document.getElementById('example')
);
Any suggestion is highly appreciated.

plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */"vendors", /* filename= */"vendor.js")
]
Use plugins, not plugin.

Related

Error while importing font or images file inside scss using Webpack 4 and react js

I am using webpack and react js.
I am getting this error when i try to import image or font file inside my scss file.
I have tried many solutions but none of them solved my problem,
webpack.common.js
enter image description here
const path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js",
vendor: "./src/vendor.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: ["html-loader"]
},
{
test: /\.(ttf|svg|png|jpg|gif)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[hash].[ext]",
outputPath: "imgs"
}
}
}
]
}
};
Here is another webpack.dev.js
module.exports = merge(common, {
mode: "development",
output: {
filename: "[name].bundle.js",
path: path.resolve(__dirname, "dist")
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/template.html"
})
],
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", //3. Inject styles into DOM
"css-loader", //2. Turns css into commonjs
"sass-loader" //1. Turns sass into css
]
}
]
}
});
ERROR in ./src/assets/index.scss (./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/lib/loader.js!./src/assets/index.scss)
Module not found: Error: Can't resolve '../../../src/assets/fonts/icomoon.ttf' in 'C:\Users\jamal\Documents\webpack-demo-app\src\assets'
# ./src/index.js
# multi (webpack)-dev-server/client?http://localhost:8080 ./src/index.js
You need to remember that the import actually takes "place" from the root index.scss file (the one that loads all the other partials). So the path you are using to fetch the asset is not accurate.
You need to use ./fonts/icomoon.ttf instead of ../fonts/icomoon.ttf
your file structure:
assets/
------/fonts
------/images
------/sass
------/---/partial1.scss // while the reference to the image is here
------/index.scss // the actual root of the reference call is here

Polyfill conflict when Embedding a react widget to a Angular 4 site

I have a embeddable widget written using react and bundle to a single js file using webpack 4.29.3 and babel 7. Everything works fine in webpack-dev-server and production by just inserting <script type="text/javascript" src="myWidget.js"></script> tag in html. My webpack config is as follows: (I have included babel-polyfill)
const HtmlWebPackPlugin = require("html-webpack-plugin");
module.exports = env => {
let htmlTemplate = "./public/index.html";
return {
entry: [ "#babel/polyfill","./src/index.js"],
output: {
path: __dirname + '/dist',
filename: 'chat.js',
library: 'Chat',
libraryTarget: 'umd',
umdNamedDefine: true
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: htmlTemplate,
filename: "./index.html",
inject: 'head'
})
]
}};
my babel config is as follows:
{
"presets": [
"#babel/env",
"#babel/preset-react"
],
"plugins": [
"#babel/plugin-proposal-class-properties"
]
}
But when I try to embed the widget to a site written in angular 4 it says TypeError: t.finally is not a function though I have include the polyfill in the react webpack build. I found the reason to be that zone.js in angular overrides the babel polyfill. When I updated the host site (angular site) zone.js version from 0.8.14 to 0.8.26 embeddable widget works fine. My question is in actual scenario I have no control on the host site where widget is embed. So in such scenario how can I overcome that?

React Module parse failed: Unexpected character '#'

I am getting an error when trying to import the following in my react component:
import FontIconPicker from '#fonticonpicker/react-fonticonpicker';
import '#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
I'm using this module: https://fonticonpicker.github.io/react-fonticonpicker/
I get this error:
./node_modules/#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css
Module parse failed: Unexpected character '#' (18:0) You may need an
appropriate loader to handle this file type. | * | / |
#font-face{font-family:fontIconPicker;src:url(assets/fontIconPicker.ttf)
format("truetype"),url(assets/fontIconPicker.woff)
format("woff"),url(assets/fontIconPicker.svg#fontIconPicker)
format("svg");font-weight:400;font-style:normal}[class="
fipicon-"],[class^=fipicon-]{font-family:fontIconPicker!important;speak:none;font-style .......
The error can be reproduced with my code from github: https://github.com/gregbia/my-app
Use npm install, and npm start and the error will show.
My webpack looks like this:
/**
* Webpack Configuration
*
* Working of a Webpack can be very simple or complex. This is an intenally simple
* build configuration.
*
* Webpack basics — If you are new the Webpack here's all you need to know:
* 1. Webpack is a module bundler. It bundles different JS modules together.
* 2. It needs and entry point and an ouput to process file(s) and bundle them.
* 3. By default it only understands common JavaScript but you can make it
* understand other formats by way of adding a Webpack loader.
* 4. In the file below you will find an entry point, an ouput, and a babel-loader
* that tests all .js files excluding the ones in node_modules to process the
* ESNext and make it compatible with older browsers i.e. it converts the
* ESNext (new standards of JavaScript) into old JavaScript through a loader
* by Babel.
*
* TODO: Instructions.
*
* #since 1.0.0
*/
const paths = require( './paths' );
const autoprefixer = require( 'autoprefixer' );
const ExtractTextPlugin = require( 'extract-text-webpack-plugin' );
// Extract style.css for both editor and frontend styles.
const blocksCSSPlugin = new ExtractTextPlugin( {
filename: './dist/blocks.style.build.css',
} );
// Extract editor.css for editor styles.
const editBlocksCSSPlugin = new ExtractTextPlugin( {
filename: './dist/blocks.editor.build.css',
} );
// Configuration for the ExtractTextPlugin — DRY rule.
const extractConfig = {
use: [
// "postcss" loader applies autoprefixer to our CSS.
{ loader: 'raw-loader' },
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
autoprefixer( {
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
} ),
],
},
},
// "sass" loader converts SCSS to CSS.
{
loader: 'sass-loader',
options: {
// Add common CSS file for variables and mixins.
data: '#import "./src/common.scss";\n',
outputStyle: 'nested',
},
},
],
};
// Export configuration.
module.exports = {
entry: {
'./dist/blocks.build': paths.pluginBlocksJs, // 'name' : 'path/file.ext'.
},
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// The dist folder.
path: paths.pluginDist,
filename: '[name].js', // [name] = './dist/blocks.build' as defined above.
},
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
devtool: 'cheap-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx|mjs)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
// #remove-on-eject-begin
babelrc: false,
presets: [ require.resolve( 'babel-preset-cgb' ) ],
// #remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
},
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
],
},
// Add plugins.
plugins: [ blocksCSSPlugin, editBlocksCSSPlugin ],
stats: 'minimal',
// stats: 'errors-only',
// Add externals.
externals: {
react: 'React',
'react-dom': 'ReactDOM',
ga: 'ga', // Old Google Analytics.
gtag: 'gtag', // New Google Analytics.
jquery: 'jQuery', // import $ from 'jquery' // Use the WordPress version.
},
};
Actually, I'm so surprised that you used SCSS webpack configs beside the PostCSS because with a little configuration you can pre-process your CSSes and then post-process them to a compressed version by SCSS syntax. I set a config you in this link. I know it is not your main problem but I think your project configuration is not optimized.
The above link of webpack config will help you to make your configuration better and you can see the webpack configs of fonts. any way...
For your exact error, you should fix your font configuration on webpack just like below:
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
exclude: /node_modules/,
loader: 'file-loader',
options: {
limit: 1024,
name: '[name].[ext]',
publicPath: 'dist/assets/',
outputPath: 'dist/assets/'
}
},
Update after work on the repo:
I write the webpack.config.dev.js file like below:
const paths = require('./paths');
const externals = require('./externals');
const autoprefixer = require('autoprefixer');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// Extract style.css for both editor and frontend styles.
const blocksCSSPlugin = new ExtractTextPlugin({
filename: './dist/blocks.style.build.css',
});
// Extract editor.css for editor styles.
const editBlocksCSSPlugin = new ExtractTextPlugin({
filename: './dist/blocks.editor.build.css',
});
// Configuration for the ExtractTextPlugin — DRY rule.
const extractConfig = {
fallback: 'style-loader',
use: [
// "postcss" loader applies autoprefixer to our CSS.
{loader: 'css-loader'},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: [
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
// "sass" loader converts SCSS to CSS.
{
loader: 'sass-loader',
options: {
// Add common CSS file for variables and mixins.
data: '#import "./src/common.scss";\n',
outputStyle: 'nested',
},
},
],
};
// Export configuration.
module.exports = {
entry: {
'./dist/blocks.build': paths.pluginBlocksJs, // 'name' : 'path/file.ext'.
},
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// The dist folder.
path: paths.pluginDist,
filename: '[name].js', // [name] = './dist/blocks.build' as defined above.
},
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
devtool: 'cheap-eval-source-map',
module: {
rules: [
{
test: /\.(js|jsx|mjs)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
// #remove-on-eject-begin
babelrc: false,
presets: [require.resolve('babel-preset-cgb')],
// #remove-on-eject-end
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
},
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract(extractConfig),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract(extractConfig),
},
{
test: /\.css$/,
include: /(node_modules\/#fonticonpicker\/react-fonticonpicker\/dist)/,
loaders: ['style-loader', 'css-loader']
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
include: /(node_modules\/#fonticonpicker\/react-fonticonpicker\/dist)/,
loader: 'file-loader',
options: {
limit: 1024,
name: '[name].[ext]',
publicPath: 'dist/assets/',
outputPath: 'dist/assets/'
}
}
],
},
// Add plugins.
plugins: [blocksCSSPlugin, editBlocksCSSPlugin],
stats: 'minimal',
// stats: 'errors-only',
// Add externals.
externals: externals,
};
And also install css-loader and file-loader.
npm install file-loader css-loader
Hint: it seems fonts need to have an outputPath in webpack configuration.
The problem is webpack is not loading your fonts #font-face in node_modules. You are excluding the loading of css from node_modules. But your #fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css is in node_modules.
Change this snippet in your webpack config
{
test: /style\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
exclude: /(node_modules|bower_components)/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
to
{
test: /style\.s?css$/,
use: blocksCSSPlugin.extract( extractConfig ),
},
{
test: /editor\.s?css$/,
use: editBlocksCSSPlugin.extract( extractConfig ),
},
{ test: /(\.css$)/, // you need to load all css imported from node_modules
loaders: ['style-loader', 'css-loader', 'postcss-loader']
}
Seems like you're missing css-loader for .css stored in node_modules. That is why you are facing this issue. Run npm i -D css-loader and add this rule to your node_modules > cgb-scrips > config > webpack.config.<env>.js file:
module: {
rules: [
// ...
{
test: /\.css$/,
use: [
{ loader: 'raw-loader' },
{ loader: 'css-loader' },
]
},
// ...
],
},
Alternatively, to skip editing webpack.config.js you could simply import your files like so:
import 'raw-loader!css-loader!#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
import 'raw-loader!css-loader!#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.material-theme.react.css';
Your loader config in webpack doesn't match the CSS file Route.
import '#fonticonpicker/react-fonticonpicker/dist/fonticonpicker.base-theme.react.css';
It is neither style.css or editor.css. Hence you get an error. Also you are ignoring node_modules in your webpack loader config but you import the css from node_modules.
Adding
{
test: /react\.s?css$/,
use: [{
loader: 'css-loader',
options: {
modules: true
}
}],
},
should work

Webpack loader fails when importing .css in react_on_rails app?

I am trying to use react-datetime on my react-on-rails app. To make the datetime work out of the box, I need to import the CSS mentioned on their GH page.
On my app, I copy/paste the CSS into a file I named DateTime.css:
...
import DateTime from 'react-datetime';
import '../../schedules/stylesheets/DateTime.css';
...
export default class AddDate extends React.Component {
But it gives me this error:
VM45976:1 Uncaught Error: Module parse failed: /Users/some/path/to/my/project/App/components/schedules/stylesheets/DateTime.css Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| .rdt {
| position: relative;
| }
It seems like the CSS loader is not working. I tried this on pure react app (create-react-app) and it worked. It broke when I did it inside react_on_rails.
This is my webpack config atm (standard out-of-the-box react_on_rails):
const webpack = require('webpack');
const { resolve } = require('path');
const ManifestPlugin = require('webpack-manifest-plugin');
const webpackConfigLoader = require('react-on-rails/webpackConfigLoader');
const configPath = resolve('..', 'config');
const { devBuild, manifest, webpackOutputPath, webpackPublicOutputDir } =
webpackConfigLoader(configPath);
const config = {
context: resolve(__dirname),
entry: {
'webpack-bundle': [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/App/startup/registration',
],
},
output: {
// Name comes from the entry section.
filename: '[name]-[hash].js',
// Leading slash is necessary
publicPath: `/${webpackPublicOutputDir}`,
path: webpackOutputPath,
},
resolve: {
extensions: ['.js', '.jsx'],
},
plugins: [
new webpack.EnvironmentPlugin({
NODE_ENV: 'development', // use 'development' unless process.env.NODE_ENV is defined
DEBUG: false,
}),
new ManifestPlugin({ fileName: manifest, writeToFileEmit: true }),
],
module: {
rules: [
{
test: require.resolve('react'),
use: {
loader: 'imports-loader',
options: {
shim: 'es5-shim/es5-shim',
sham: 'es5-shim/es5-sham',
},
},
},
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: 'css-loader',
exclude: /node_modules/,
},
],
],
},
};
module.exports = config;
if (devBuild) {
console.log('Webpack dev build for Rails'); // eslint-disable-line no-console
module.exports.devtool = 'eval-source-map';
} else {
console.log('Webpack production build for Rails'); // eslint-disable-line no-console
}
I am very new in webpack, and not sure how to I can add loaders to make it work, how can I apply the DateTime.css file that I have to be applied to react-datetime?
EDIT: added css-loader (also updated the webpack above). It is no longer complaining that I don't have the correct loader, but the CSS does not work.
{
test: /\.jsx?$/,
use: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: 'css-loader',
exclude: /node_modules/,
},
],
There are 2 conceptually different ways to approach this.
1. Using CSS modules.
This way your CSS will end up bundled with your JS and as soon as webpack loads that JS module/bundle it will automatically append CSS style element into the head.
In my project I have this rule to do exactly that (note that we use both css-loader and style-loader):
{
test: /\.css$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[path][name]__[local]--[hash:base64:5]'
}
}]
}
More on css-loader modules at this link.
2. Using ExtractTextPlugin. This way all your CSS will be extracted into a separate file. The configuration requires 2 things: a plugin and loaders configuration created by the plugin:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
// Add this to your webpack plugins array
new ExtractTextPlugin('styles.css')
And add this to your rules:
{
test: /\.css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader']
})
}
This will create one single styles.css file and put all CSS you import from JS into that file.

_angular.angular undefined error when loading angular app built by webpack

I am trying to bootstrap an AngularJS app built with Webpack. But I get the following error and the module isn't set up.
TypeError: _angular.angular is undefined
I dig into the generated code chunk and find that the _angular.angular is from
var _angular = __webpack_require__(1);
var _angularUiBootstrap = __webpack_require__(3);
_angular.angular.module('app', [_angularUiBootstrap.bootstrap]).constant('_', window._).run(function ($rootScope) {
$rootScope._ = window._;
It looks like that _angular.angular.module should be _angular.module. I probably use a wrong way to bootstrap angular, or use an incorrect Webpack configuration. Here is my code:
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var srcDir = 'static_src';
var outputDir = 'static';
module.exports = {
devtool: 'source-map',
debug: true,
entry: {
app: path.resolve(srcDir, 'app.js')
},
output: {
path: outputDir,
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
resolve: {
extensions: ['', '.js', '.less', '.css'],
alias: {
npm: __dirname + '/node_modules'
}
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ['syntax-decorators', 'ng-annotate']
},
exclude: /node_module/
},
{ test: /\.less$/, loader: 'to-string!css!less' },
{ test: /\.css$/, loader: ExtractTextPlugin.extract('style-loader', 'css-loader') },
{ test: /\.(png|gif|jpg)$/, loader: 'file?name=images/[name].[ext]' }
]
},
plugins: [
new webpack.NoErrorsPlugin(),
new webpack.optimize.DedupePlugin(),
new ExtractTextPlugin('[name].css')
]
};
app.js
import { angular } from 'angular';
import { bootstrap } from 'angular-ui-bootstrap';
angular.module('app', [bootstrap]);
I am using angular 1.5.0 and webpack 1.12.14.
Thanks in advance.
your error is in the require statement. you are using
import { angular } from 'angular';
this implies that there is an angular variable inside of the exported angular module.
what you want to use is
import angular from 'angular';
try that.

Resources