How to conditionally use a bundle in webpack - javascript

I have an app.bundle.js (basically the main app bundle) and two cordova bundles: iosCordova.bundle.js and androidCordova.bundle.js. I only script src one of them depending on whether the user is logging in on an ios or android. I have all the bundles, css's, png's and everything except index.html in a generated folder (named _dist). I can't put index.html using htmlWebpackPlugin in this folder because otherwise there would be an automatic script src to both the cordova bundles (which is something I want to avoid). My problem is building the project: when I run build it is looking for index.html in _dist which results in 404. FYI When I run "npm run dev" however it knows that it should look for index.html in the main folder while app.bundle.css and app.css should be in _dist.
my webpack.config:
config.entry = {
app: './app.js',
iosCordova: ['./static/wrapper/js/ios/cordova_all.min.js'],
androidCordova: ['./static/wrapper/js/android/cordova_all.min.js']
};
config.output = {
path: __dirname + '/_dist',
publicPath: 'localhost:8080/',
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js'
};
config.module = {
noParse: /node_modules\/html2canvas/,
preLoaders: [],
loaders: [
{
test: /\.js$/,
loader: 'babel?optional[]=runtime',
presets: ['es2015'],
exclude: [
/node_modules/,
/cordova_all/
]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$/,
loader: 'file?name=[name].[ext]'
}, {
test: /\.html$/,
loader: "ngtemplate?relativeTo=" + __dirname + "!raw"
}]
};
var cssLoader = {
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss', 'scss', 'sass')
};
config.module.loaders.push(cssLoader);
config.devServer = {
stats: {
modules: false,
cached: false,
colors: true,
chunk: false
}
};
//config.resolve = {
// alias: {
// moment: "node_modules/moment/min/moment.min.js"
// //"jquery-ui": "vendor/plugins/jquery-ui.min.js"
// }
//};
return config;
};
index.html:
<!DOCTYPE html>
...
<html>
<head>
<script type="text/javascript">
(function(){
if (window.location.search.indexOf('cordova=') > -1) {
var platform = /i(phone|pod|pad)/gi.test(navigator.appVersion) ? 'iosCordova.bundle.js' : 'androidCordova.bundle.js';
var cordovaScript = document.createElement('script');
cordovaScript.setAttribute('src',platform);
document.head.appendChild(cordovaScript);
}
}());
</script>
<link href="app.css" rel="stylesheet">
</head>
...
<script src="app.bundle.js"></script>
</body>
</html>

So the answer is:
config.plugins.push(
new HtmlWebpackPlugin({
template: './index.html',
inject: true,
excludeChunks: ['app','iosCordova','androidCordova']
})
);

Related

webpack-dev-server injects CSS webpack doesn't

I'm new to webpack and I'm facing an issue while trying to build a simple webpage.
While I don't have problems when using webpack-dev-server, when I build my application with webpack I don't see the CSS inside the index.html file.
Here is the webpack.conf.js:
var path = require( "path" );
const HtmlWebpackPlugin = require( 'html-webpack-plugin' );
module.exports = {
entry: {
index: path.join( __dirname, "src", "index.js" )
},
output: {
path: path.join( __dirname, "dist" ),
filename: "bundle.js"
},
devServer: {
host: '0.0.0.0',
port: 9000,
writeToDisk: true
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/,
exclude: /(node_modules)/,
use: ['file-loader'],
},
{
test: /\.svg$/,
exclude: /(node_modules)/,
loader: 'svg-inline-loader'
},
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: "babel-loader",
options: { presets: ["#babel/preset-env"] }
}
},
{
test: /\.styl$/,
exclude: /(node_modules)/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"stylus-loader" // compiles Stylus to CSS
]
}
]
},
plugins: [
new HtmlWebpackPlugin( {
filename: 'index.html',
template: path.join( __dirname, "src", "index.html" ),
inject: true
} ),
]
};
This is the index.js:
import "./css/index.styl";
import "./css/graphics.styl";
import "./js/polyfills.js"
import "./js/manager.js"
console.log( "TEEEEEEEEEEEEEEEEST" );
Here the index.html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport"
content="user-scalable=no, width=device-width,initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
</head>
<body>
<div id="graphicsContainer" class="graphics-container">
<%=require('./assets/images/barca_onde.svg')%>
</div>
</body>
</html>
I run the dev mode with this command:
./node_modules/webpack-dev-server/bin/webpack-dev-server.js --config /app/webpack.config.js --mode development --color --watch
While the build command I use is this:
./node_modules/webpack/bin/webpack.js --config /app/webpack.config.js --mode production --color
Both commands don't show any error, but the first generates the bundle.js, the inline SVG, the CSS code and injects them in the index.html while the second only generates bundle.js and the SVG and injects them in index.html leaving the CSS out.
What am I missing? Thank you in advance!
This is happening because your configuration isn't set up to write your compiled CSS to a file. The injection of style only happens in development mode, which is why you aren't seeing it when you build in production mode.
If you're using the latest major release of webpack (which is 4 as of this answer), you'll want to use MiniCssExtractPlugin. It replaces style-loader in your configuration.
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV === 'development';
// ...
{
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css',
chunkFilename: devMode ? '[id].css' : '[id].[hash].css',
}),
],
rules: [
{
test: /\.styl$/,
exclude: /(node_modules)/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: { hmr: devMode },
},
"css-loader",
"stylus-loader"
]
}
]
}
For prior major releases of webpack, see ExtractTextWebpackPlugin.

Workbox service worker + manifest.json setup webpack 4

I’m trying to create a webpack builder with workbox, as i can see Vue CLI 3 is using.
In my package.json file, i’ve made a “build” to build and compile the files and a “dev” to run it.
"build": "webpack --mode development",
"dev": "nodemon --inspect --watch webpack.config.js main.js"
I use InjectManifest from workbox-webpack-plugin to handle the build in my webpack.config.js file. I've tryed different options to see what they did.
webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin')
const {GenerateSW, InjectManifest} = require('workbox-webpack-plugin')
module.exports = {
mode: 'production',
entry: {
app: [
'#babel/polyfill',
'./src/main.js'
]
},
output: {
path: path.resolve(__dirname, 'dist/'),
filename: '[name]-[hash].js',
publicPath: '/'
},
devServer: {
inline: false,
contentBase: "./dist",
overlay: true,
hot: true,
stats: {
colors: true
}
},
module: {
rules: [
{
test: /\.html$/,
use: {
loader: 'html-loader'
}
},
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['#babel/preset-env']
}
},
{
test: /\.css$/,
loader: [
'style-loader',
'css-loader'
]
},
{
test: /\.scss$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader", options: {
sourceMap: true
}
},
{
loader: "sass-loader", options: {
sourceMap: true
}
}
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HTMLWebpackPlugin({
template: './public/index.html'
}),
// new GenerateSW({
// include: [/\.html$/, /\.js$/, /\.css$/],
// exclude: '/node_modules'
// }),
new InjectManifest({
swSrc: './src/js/registerServiceWorker.js',
swDest: '/serviceworker.js',
exclude: '/node_modules'
})
// service worker caching
// new SWPrecacheWebpackPlugin(
// {
// cacheId: 'webpack-project',
// filename: 'service-worker.js',
// staticFileGlobs: [
// 'dist/**/*.{js,css}',
// '/'
// ],
// minify: true,
// stripPrefix: 'dist/',
// dontCacheBustUrlsMatching: /\.\w{6}\./
// }
// )
]
}
When i build the project, i creates the following files:
app-e8dd91....js
index.html
precache-manifest.d92js8....js
serviceworker.js
index.html file only adds the app-e8d91....js file as a script leaving the precached manifest file and service worker not being used, which results in that there's no service worker to my localhost.
I have a registerServiceWorker.js file which is being referenced in the injectManifest plugin.
registerServiceWorker.js
import { register } from "register-service-worker";
const path = require('path')
register(path.resolve(__dirname, 'service-worker.js'), {
ready() {
console.log(
"App is being served from cache by a service worker."
);
},
cached() {
console.log("Content has been cached for offline use.");
},
updated() {
console.log("New content is available; please refresh.");
},
offline() {
console.log(
"No internet connection found. App is running in offline mode."
);
},
error(error) {
console.error("Error during service worker registration:", error);
}
});
How do i make my build create and add the service worker + manifest.json file, so it works on localhost and also works offline?
File structure:
webpack.config.js
server.js (handle server + webpackHotMiddleware + express)
dist (builded folder)
src (folder)
main.js
js (folder)
registerServiceWorker.js
public (folder)
index.html
manifest.json
favicon.ico

React component is undefined in html script tag

I need to render React component in my view (html file). I'm using webpack 1 and getting error of component undefined. I tried to use window.component, but it didn't work too. If I use RenderDOM inside my component, all works well.
My component:
export class SmallCart extends BaseComponent {
...
render() {...}
}
Webpack 1 config:
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var BowerWebpackPlugin = require('bower-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var webpack = require('webpack');
module.exports = {
devtool: 'source-map',
entry: {
...
myComponent: "./wwwroot/js/es6/SmallCart/SmallCart.jsx",
...
},
output: {
path: __dirname + "/dist",
filename: '[name].js',
chunkFilename: '[id].chunk.js'
},
module: {
loaders: [
{
test: /\.(png|jpg|gif|ico)$/,
loader: "file-loader?name=assets/[name]-[hash:6].[ext]"
}, {
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader?limit=10000&minetype=application/font-woff&name=assets/[name]-[hash:6" +
"].[ext]"
}, {
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader?name=assets/[name]-[hash:6].[ext]"
}, {
test: /\.scss$/i,
loader: ExtractTextPlugin.extract(['css-loader?-autoprefixer!postcss-loader', 'sass'])
}, {
test: /\.css$/i,
loader: ExtractTextPlugin.extract(['css-loader?-autoprefixer!postcss-loader'])
}, {
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
},
progress: true,
resolve: {
modulesDirectories: ['node_modules'],
extensions: ['', '.json', '.js']
},
externals: {
jquery: "jQuery",
react: "React",
reactDOM: "ReactDOM"
},
plugins: [
new webpack.ProvidePlugin({'window.Nette': 'nette-forms', 'window.jQuery': 'jquery', jQuery: 'jquery', $: 'jquery'}),
new webpack
.optimize
.CommonsChunkPlugin({
filename: "commons.js", name: "commons",
}),
new ExtractTextPlugin("frontend.css"),
]
}
And in my view I have this:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.js" charset="utf-8"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js" charset="utf-8"></script>
<script type="text/javascript" src="/dist/commons.js" charset="utf-8"></script>
<script type="text/javascript" src="/dist/SmallCart.js" charset="utf-8"></script>
<script type="text/javascript">
window.data_for_react = {};
ReactDOM.render(React.createElement(SmallCart, { dataSource : data_for_react}, document.getElementById('box-to-rendering')));
</script>
But in render method is component undefined.
What is wrong? Is possible render component in view?
Thank you for your time.
EDIT
Ok, now I try use window.SmallBasket and webpack config update to:
...
new webpack
.optimize
.CommonsChunkPlugin({
names: [
"commons"
],
minChunks: Infinity
}),
...
And it works. But I still cannot solve it without window property.
Try putting all your react code from your view in something like this:
document.addEventListener('DOMContentLoaded', () => {
//... your ReactDOM.render stuff here
};
You need to wait for the DOM elements to load before you can getElementById.

Webpack dev server not serving output

I have an application that's structured like this:
- root
- app/
- config/
- css/
- js/
- public/
- package.json
- webpack.config.js
The React app is in the app folder and I'm publishing to the public folder. Here is my webpack configuration:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var extractSass = new ExtractTextPlugin(
"../css/style.css", {
allChunks: true
});
module.exports = {
context: path.join(__dirname, "public"),
devtool: debug ? "inline-sourcemap" : null,
entry: {
withify: '../app/main.jsx',
fbauth: '../app/fbauth.jsx',
fbuser: '../app/fbuser.jsx',
fontawesome: 'font-awesome-webpack!../node_modules/font-awesome-webpack/font-awesome.config.js',
styles: './css/style.scss'
},
output: {
path: './js',
filename: '[name].js'
},
resolve: {
alias: {
config: path.join(__dirname, 'config', process.env.NODE_ENV || 'development')
}
},
module: {
loaders: [
{
test: /\.json$/,
loader: 'json'
},
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: ['react-html-attrs', 'transform-class-properties', 'transform-decorators-legacy'],
}
},
{
test: /\.scss$/,
loader: extractSass.extract(["css", "sass"])
},
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpg)?(\?v=[0-9]\.[0-9]\.[0-9])?$/i,
loader: 'url'
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
}]
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
extractSass
],
externals: {
fs: '{}',
tls: '{}',
net: '{}',
console: '{}'
}
};
Here is how I'm trying to start the app with npm run dev:
"scripts": {
"dev": "./node_modules/.bin/webpack-dev-server --content-base public --inline --hot"
},
However, when my index.html tries to access the withify.js file that should be available in memory in the development server I'm getting a 404; what did I do wrong here?
<html>
<head>
<title>Withify Application</title>
<!-- Mobile Specific Metas ================================================== -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyAlPNWOZmv60OUaD3_idHMP15-Ghwm7RDE&libraries=places"></script>
<link type="text/css" rel="stylesheet" href="/css/style.css">
</head>
<body>
<div id="app"></div>
<script src="/js/jquery.min.js"></script>
<script src="/js/withify.js"></script>
<script defer src="https://code.getmdl.io/1.1.3/material.min.js"></script>
</body>
</html>
Ok well a couple things:
Context is the folder where you tell webpack where to look for your entries. So currently you are telling webpack to look into the public folder, but all of your entries live in "/app"
So your context would be something like:
context: path.join(_dirname, 'app')
This tells webpack look into root/app and find the entries which should now look like:
entry: [
withify: 'main.jsx',
fbauth: 'fbauth.jsx',
fbuser: 'fbuser.jsx',
]
And your output will be something like this:
output:[
path: path.join(__dirname, 'public', 'js')
filename: '[name].js'
]
I think that should fix your issues as long as you are pulling everything from your public folder!
EDIT:
Try setting this as well in your output:
output:[
path: path.join(__dirname, 'public', 'js'),
filename: '[name].js',
publicPath: '/js/'
]

Webpack loads from the wrong URL when the path changes

I'm writing a react app and everything works fine when I navigate to localhost:3000, but when I try to go to localhost:3000/foo/page, I get an error message that tells me localhost:3000/foo/bundle.js cannot be loaded.
To me, this looks like a problem with Webpack looking in the wrong place for bundle.js, but I'm not sure. How do I get the app to always look at localhost:3000 for bundle.js?
This is some of my webpack config.
var TARGET = process.env.npm_lifecycle_event;
var ROOT_PATH = path.resolve(__dirname);
var APP_PATH = path.resolve(ROOT_PATH, 'app');
var BUILD_PATH = path.resolve(ROOT_PATH, 'dist');
process.env.BABEL_ENV = TARGET;
var common = {
entry: APP_PATH,
output: {
path: BUILD_PATH,
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: ['babel'],
include: APP_PATH
},
{
test: /\.svg$/,
loader: 'url-loader?limit=8192',
include: APP_PATH
},
{
test: /\.png$/,
loader: 'url-loader?limit=8192',
include: APP_PATH
},
{
test: /\.ico$/,
loader: 'url-loader?limit=8192',
include: APP_PATH
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'foobar',
template: path.resolve(APP_PATH, 'index.html'),
favicon: path.resolve(APP_PATH, 'images', 'favicon.ico')
})
]
};
if (TARGET === 'start' || !TARGET) {
module.exports = merge(common, {
devtool: 'eval-source-map',
module: {
loaders: [
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass'],
include: APP_PATH
}
]
},
devServer: {
historyApiFallback: true,
hot: true,
inline: true,
port: 3000,
progress: true
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
});
}
Add output.publicPath: '/' to your webpack config.
output: {
path: BUILD_PATH,
publicPath: '/',
filename: 'bundle.js'
}
HtmlWebpackPlugin most probably generates the file which have:
<script src="bundle.js"></script>
Setting up output.publicPath: '/' will make it:
<script src="/bundle.js"></script>
From Webpack Config page:
output.publicPath
The publicPath specifies the public URL address of
the output files when referenced in a browser. For loaders that embed
or tags or reference assets like images, publicPath is
used as the href or url() to the file when it’s different then their
location on disk (as specified by path). This can be helpful when you
want to host some or all output files on a different domain or on a
CDN. The Webpack Dev Server also takes a hint from publicPath using it
to determine where to serve the output files from. As with path you
can use the [hash] substitution for a better caching profile.

Categories