I would like to divide my scss styles into chunks. Therefore, I created a separate subpage.scss imported by subpage.js file (one of the entries). I use miniCssExtractPlugin to extract SCSS styles from JS and create style bundles for each file. I map them in my BundleConfig to specific style chunks referenced in HTML.
The whole process works for the main.js and main.scss but not for subpage.js and subpage.scss - it leaves styles in .js file and the styles are loaded twice (both from JS and from HTML). The only difference between these cases is that the main.js is loaded as an entry in webpack.config.js and subpage.js is loaded with the remaining entries in webpack.DefinePlugin().
Any idea why MiniCssExtractPlugin doesn't extract the styles from a .js file loaded using this method and extracts styles for the main entry correctly?
My webpack.config.js
const readEntries = require('./entries');
const path = require('path');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const entries = readEntries('../Scripts/entries');
module.exports = (mode) => ({
name: 'name',
context: path.resolve(__dirname, '../Scripts'),
resolve: {
extensions: ['.js', '.json', '.html', '.vue'],
alias: {
'~': path.resolve(__dirname, '../Scripts'),
'vue$': 'vue/dist/vue.esm.js',
'#trackers': path.resolve(__dirname, '../Scripts/trackers')
},
},
entry: {
main: './main.js',
},
output: {
path: path.resolve(__dirname, '../Content/bundle'),
publicPath: '/Content/bundle/',
filename: '[name].bundle.js',
chunkFilename: process.env.NODE_ENV === 'production' ? '[id].js?v=[contenthash]' : '[name].js?v=[contenthash]'
},
plugins: [
new CleanWebpackPlugin(),
new webpack.ProgressPlugin(),
new webpack.DefinePlugin({
'process.env': {
'ENTRIES': JSON.stringify(entries),
'NODE_ENV': JSON.stringify(mode)
}
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: '[contenthash].[name].bundle.css',
}),
new BundleAnalyzerPlugin({
openAnalyzer: false,
analyzerMode: 'static'
})
],
module: {
rules: [
{
test: require.resolve('vue'),
use: [
{
loader: `expose-loader`,
options: 'Vue'
}
]
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(js)$/,
use: [
'babel-loader'
],
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[contenthash]'
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
optimization: {
splitChunks: {
chunks: 'async'
}
},
performance: {
hints: false
},
externals: {
jquery: 'jQuery',
DM: 'DM'
},
stats: {
modules: false
},
target: 'web'
});
my BundleConfig:
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.IgnoreList.Clear();
BundleTable.EnableOptimizations = true;
bundles.Add(new ScriptBundle("~/bundles/js/head").Include(
"~/Scripts/head.js"
));
bundles.Add(new Bundle("~/bundles/js/scripts").Include(
"~/Content/bundle/main.bundle.js"
));
bundles.Add(new StyleBundle("~/bundles/css/main").Include(
"~/Content/bundle/*main.bundle.css"
));
bundles.Add(new StyleBundle("~/bundles/css/trends").Include(
"~/Content/bundle/*trends.bundle.css"
));
}
}
Related
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've got webpack up and running and can't quite figure our how to get .scss file compiled to be used with custom styling such as colors etc. Bootstrap is otherwise loaded fine.
Here's my webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = (env = {}, argv = {}) => {
const isProd = argv.mode === 'production';
const config = {
mode: argv.mode || 'development', // we default to development when no 'mode' arg is passed
optimization: {
minimize: true
},
entry: {
main: './src/main.js'
},
output: {
filename: isProd ? 'bundle-[chunkHash].js' : '[name].js',
path: path.resolve(__dirname, '../wwwroot/dist'),
publicPath: "/dist/"
},
plugins: [
new MiniCssExtractPlugin({
filename: isProd ? 'style-[contenthash].css' : 'style.css'
}),
new CompressionPlugin({
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.js$|\.css$|\.html$|\.eot?.+$|\.ttf?.+$|\.woff?.+$|\.svg?.+$/,
threshold: 10240,
minRatio: 0.8
}),
new HtmlWebpackPlugin({
template: '_LayoutTemplate.cshtml',
filename: '../../Views/Shared/_Layout.cshtml', //the output root here is /wwwroot/dist so we ../../
inject: false
})
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'sass-loader'
]
},
{
test: /\.(png|jpg|gif|woff|woff2|eot|ttf|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'assets/'
}
}
]
}
};
return config;
};
I have node-sass installed which I think compiles it? Just not sure how to get it going.
Thanks,
You need to import your CSS into your entrypoint. So in main.js, import your scss file like this...
import './path-to/file.scss
Well, as the title says, webpack is not producing what I expect.
Here's my config:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const extractPlugin = new ExtractTextPlugin({
filename: 'main.css',
});
process.env.NODE_ENV = 'production';
module.exports = {
entry: {
main: './src/main.js',
algo: './src/algo.js',
},
entry: './src/main.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
module: {
rules: [
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015'],
}
}
],
},
{
test: /\.scss$/,
use: extractPlugin.extract({
use: [
'css-loader',
'sass-loader',
]
})
},
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.php$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
outputPath: '/'
}
}
]
},
{
test: /\.(jpg|png|gif|jpeg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
outputPath: 'images/',
}
}
]
}
],
},
resolve: {
alias: {
vue: 'vue/dist/vue.min'
}
},
plugins: [
extractPlugin,
new HtmlWebpackPlugin({
template: 'src/index.html',
filename: 'index.html',
chunks: ['main'],
}),
new HtmlWebpackPlugin({
template: 'src/algo.html',
filename: 'algo.html',
chunks: ['algo']
}),
new CleanWebpackPlugin([
'dist',
]),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
Vue: 'vue',
}),
new CopyWebpackPlugin([
{
from: 'src/*.php',
to: '[name].[ext]',
test: /\.php$/
}
]),
],
mode: 'production',
};
Both main.js and algo.js are simply a set of #import 'something's (Please let me know if this a good practice in the comment).
I want to insert the resulting bundles, main.js and algo.js to go into
index.html and algo.html, respectively.
However, so far it's been only producing main.js for index.html so far.
Previously, the output was as follows:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
However, that didn't work either.
Can someone help me achieve the desired outcome?
You've specified entry twice in your configuration:
entry: {
main: './src/main.js',
algo: './src/algo.js',
},
entry: './src/main.js',
The second entry here is overwriting the first, which means you've only configured ./src/main.js.
As we are putting this output on a load balancer (not using sticky), we need to place the output of these files without chunks (neither hashes).
These are the main two files for webpack configuration.
webpack.common.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const helpers = require('./helpers');
const STATIC_TRANSLATION_MAP = require('../TranslationMap.json');
module.exports = {
entry: {
app: ['./src/public/main.ts'],
vendor: './src/public/vendor.ts',
polyfills: './src/public/polyfills.ts'
},
output: {
path: helpers.root('dist/public')
},
module: {
rules: [
{
test: /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader', 'angular2-router-loader']
},
{
test: /\.html$/,
loader: 'html-loader?-minimize'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=assets/[name].[ext]'
},
{
test: /\.styl$/,
include: helpers.root('src', 'public', 'app'),
use: [
'raw-loader',
'stylus-loader'
]
},
{
test: /\.styl$/,
include: helpers.root('src', 'public'),
exclude: helpers.root('src', 'public', 'app'),
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'stylus-loader'
]
})
},
{
test: /\.css$/,
include: helpers.root('src', 'public', 'assets', 'css'),
loader: 'raw-loader'
},
{
test: /\.xlf$/,
loader: 'raw-loader'
}
]
},
resolve: {
extensions: ['.webpack.js', '.web.js', '.ts', '.js'],
alias: {}
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/public/index.html'
}),
new webpack.DefinePlugin({
'process.env': {
'LOCALE_LIST': JSON.stringify(Object.keys(STATIC_TRANSLATION_MAP))
}
})
]
};
webpack.prod.js
const webpack = require('webpack');
const webpackMerge = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const commonConfig = require('./webpack.common.js');
const helpers = require('./helpers');
const prodEnv = 'production';
module.exports = webpackMerge(commonConfig, {
devtool: 'source-map',
output: {
filename: '[name].js',
chunkFilename: '[name].js'
},
plugins: [
new webpack.NoEmitOnErrorsPlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: {
keep_fnames: true
}
}),
new webpack.LoaderOptionsPlugin({
htmlLoader: {
minimize: false
}
}),
new ExtractTextPlugin('[name].css'),
new webpack.DefinePlugin({
'process.env': {
'ENV': JSON.stringify(prodEnv)
}
})
]
});
But for my surprise, I noticed webpack is producing extra files. Can you see those ones with numbers? (From 0 to 19). I'm not sure from where they're coming from, and every content of those starts with webpackJsonp.
Is there a way to disable this chunk feature and just produce the three files from entry?
What is happening?
But for my surprise, I noticed webpack is producing extra files. Can you see those ones with numbers? (From 0 to 19)
output.chunkFilename
This option determines the name of non-entry chunk files.
By default [id].js is used or a value inferred from output.filename (name is replaced with id):
Non-entry chunks (external)
./dist/[0].js
./dist/[1].js
./dist/[2].js
./dist/[3].js
...
Entry-chunks from webpack.config.entry
./dist/app.js
./dist/vendor.js
...
How to fix it?
Currently CommonChunkPlugin only receives modules imported from entry chunks.
webpack/issues/4392
Workarounds / hacks
This concept may be used to obtain implicit common vendor chunks:
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: function (module) {
// this assumes your vendor imports exist in the node_modules directory
return module.context && module.context.indexOf("node_modules") !== -1;
}
})
Passing the minChunks property a function
webpack/issues/2855#issuecomment-239606760
https://stackoverflow.com/a/39401288/6836839
I am new to webpack & want to add all the css files bundled and added to to the index.html file in dist.
my webpack.config.js file
var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const helpers = require('./helpers');
module.exports = function(env) {
return {
entry: {main:'./app/index.js',
vendor: 'moment'
},
resolve: {
extensions: ['.css', '.js']
},
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
include: helpers.root('app'),
use: ExtractTextPlugin.extract({
fallback: "css-loader",
use: 'style-loader'
})
},
{
test: /\.html$/,
loader: 'html-loader'
}
]},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
names: ['vendor', , 'manifest']
}),
new ExtractTextPlugin('styles.css'),
new HtmlWebpackPlugin({
template: 'app/index.html',
inject: 'body'
})
]
}
};
However it does not create styles.css file.
Thanks in advance.