How to avoid loading from chunk in webpack? [Angular] [inline js] - javascript

I am trying to bundle a angular project into a single file (js, css and html). I've managed to get the html and css working and js is also inline now (using HtmlWebpackInlineSourcePlugin). The js files generated after minification are like below:
The vendor, main and polyfill are inline in the index.html. But I see that the generated js for main and vendor js are trying to load from the chunk 3.js (this has the actual js that's written for the app).
I want this chunk also to be inline, but can't seem to find a way to do it. Even if I did manage to make it inline, how do I avoid vendor/main js from loading this chunk. The webpack config is below.
'use strict';
const webpackMerge = require('webpack-merge');
const ngw = require('#ngtools/webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackInlineSourcePlugin = require('html-webpack-inline-source-plugin');
const isDev = process.env.NODE_ENV !== 'production';
//just a wrapper for path
const helpers = require('./helpers');
module.exports = {
mode: 'production',
output: {
path: helpers.root('dist'),
filename: '[name].js',
},
resolveLoader: {
modules: [helpers.root('node_modules')]
},
entry: {
vendor: './src/vendor.ts',
polyfills: './src/polyfills.ts',
main: './src/main.ts'
},
resolve: {
extensions: ['.ts', '.js', '.scss']
},
module: {
rules: [
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(scss|sass)$/,
use: [
{ loader: 'style-loader', options: { sourceMap: isDev } },
{ loader: 'css-loader', options: { sourceMap: isDev } },
{ loader: 'sass-loader', options: { sourceMap: isDev } }
],
include: helpers.root('src', 'assets')
},
{
test: /\.(scss|sass)$/,
use: [
'to-string-loader',
{ loader: 'css-loader', options: { sourceMap: isDev } },
{ loader: 'sass-loader', options: { sourceMap: isDev } }
],
include: helpers.root('src', 'app')
},
{
test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/,
loader: '#ngtools/webpack'
}
]
},
plugins: [
new ngw.AngularCompilerPlugin({
tsConfigPath: helpers.root('tsconfig.json'),
entryModule: helpers.root('src', 'app', 'app.module#AppModule')
}),
new HtmlWebpackPlugin({
template: 'src/index.html',
inlineSource: '.(js|css)$',
}),
new HtmlWebpackInlineSourcePlugin(HtmlWebpackPlugin),
// new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/chunk/])
]
};
FYI - I want it to be a single inline file because I need to use in google apps script (editor add on).

I ended up solving this using libraryTarget in webpack to compile to umd.
output: {
path: helpers.root('dist'),
publicPath: '/',
filename: '[name].js',
libraryTarget: "umd",
globalObject: 'this'
}

Related

Webpack issues with css/scss on public folder load

I need help with my webpack.
Currently I have a simple structor but doesn't load the css into the public folder
instead loads 2 inline tags.
My Issue is:
the public folder as a index.html with two css with for some reason the get duplicated with my bundle.js.
How do I set a normal css in there?
Surely my webpack is wrong.
I'm using react and I have a sass folder with all scss files.
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
entry: ["./src/index.js"],
mode: "development",
module: {
rules: [{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
sideEffects: true,
},
{
// Images
test: /\.(png|svg|jpg|gif)$/,
use: {
'loader': 'file-loader',
'options': {
'name': "[name].[ext]",
'outputPath': 'assets/images/'
}
}
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
},
},
},
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader",
options: {
presets: ["#babel/env"]
}
}
],
},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
output: {
path: path.resolve(__dirname, "public/"),
publicPath: "/public/",
filename: "bundle.js"
},
devServer: {
historyApiFallback: true,
contentBase: path.join(__dirname, "public/"),
port: 3000,
hot: true
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "src", "pages/index.html")
})
]
};

split style[hash].css into dynamically loaded chunks

I am trying to split code of styles into smaller chunks due to the size of generated output. I am developing using react so i solved javascript loading with React.lazy().
Lets say that there is one big application with 50 different views you can open. Not all views are available to all users.
What i did in my router is:
...
const view = React.lazy(() => import("./views/view"));
...
...
<view />
...
What this did is divided entire application to 50 separate js files that are dynamically loaded which is good.
It however did not divide styles the same way. So lets look into one of the views:
import React, { Component } from "react";
import "../../scss/view.scss";
class view extends Component {
...
}
export default view;
So each view has its own scss files dedicated for this view, which makes them virtually standalone. The problem is that webpack is still producing only one big style[hash].css file.
Webpack config:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html"
});
const extractTextPlugin = new ExtractTextPlugin({
filename: "css/style.[hash:8].css",
allChunks: true
});
module.exports = {
output: {
filename: "js/main.[hash:8].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.(png|jpg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]"
}
},
{
test: /\.(scss|sass|css)$/i,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{ loader: "css-loader" },
{ loader: "postcss-loader", options: { sourceMap: true } },
{ loader: "sass-loader", options: { sourceMap: true } }
]
})
}
]
},
resolve: {
extensions: [".js", ".jsx", ".json"]
},
plugins: [htmlPlugin, extractTextPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }]
}
}
};
Is there any way to make styles also produced and loaded dynamically respective to their js file, so for example if i open view 10 it loads 10.main[hash].js and 10.style[hash].css ?
Answer to this problem is to replace deprecated extract-text-webpack-plugin package that is actually missing this functionality (splitting styles into respective chunks).
Instead mini-css-extract-plugin should be used and it automatically works.
updated working webpack config file:
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const htmlPlugin = new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "index.html",
});
const miniCssExtractPlugin = new MiniCssExtractPlugin({
filename: "css/style.[hash:8].css",
chunkFilename: "css/[id].style.[hash:8].css",
});
module.exports = {
output: {
filename: "js/main.[hash:8].js",
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.(png|jpg|jpeg|gif|ico|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 25000,
outputPath: "/assets/",
name: "[name].[hash:8].[ext]",
},
},
{
test: /\.(scss|sass|css)$/i,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"sass-loader",
],
},
],
},
resolve: {
extensions: [".js", ".jsx", ".json"],
},
plugins: [htmlPlugin, miniCssExtractPlugin],
devServer: {
historyApiFallback: {
rewrites: [{ from: /^\/$/, to: "/index.html" }],
},
},
};

Webpack url() path resolution with css-loader

I am developing a site and using webpack for obvious reasons. The problem I am having is with path resolution for images which are imported into my project via my SCSS files. The issue is that css-loader isn't resolving the correct path. What seems to be happening is the following:
If I allow css-loader to handle the url() imports (leaving the url option to true) it rewrites the file path relative to the output directory specified in ExtractCSSChunksPlugin(), for example:
url('../img/an-image.jpg') should be rewritten to url('http://localhost:3000/assets/img/an-image.jpg'), however, what is actually being outputted is url('http://localhost:3000/assets/css/assets/img/an-image.jpg').
If I change it to false the correct path is resolved but the file-loader isn't able to find the images and then emit them.
I know that the images are being outputted when the css-loader is handling url resolution as I can see the emitted message when the bundle is compiled -- it does not fail.
I can also get the images to display if I manually add import calls to them in the JS entry point, set in the entry: field, and then call the absolute path in SCSS. But this is not desirable as it becomes tedious with the growing project.
I have tried to use resolve-url-loader and changing multiple settings but I just can't seem to get this to work.
I have also tried using the resolve: { alias: { Images: path.resolve(__dirname, 'src/assets/img/' } } option provided by webpack and then calling url('~Images/an-image.jpg') in my SCSS but it just reproduces the same results.
So, overall, my issue is that I need to be able to use relative paths in my SCSS and then have them rewritten to the correct path by one of my loaders.
My current webpack config (outputting the files with file loader but prepending assets/css/ to the start of the url) is as follows:
"use strict";
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');
const ExtractCSSChunksPlugin = require('extract-css-chunks-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
entry: [
'webpack-hot-middleware/client',
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
}
}
},
{
test: /\.scss$/,
use: [
{
loader: ExtractCSSChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
},
{
test: /\.html$/,
use:['html-loader']
},
{
test:/\.(svg|jpg|png|gif)$/,
use: [{
loader:'file-loader',
options: {
publicPath: 'assets/img',
outputPath: 'assets/img',
name: '[name].[ext]',
esModule: false
}
}],
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ExtractCSSChunksPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[id].css',
}),
]
});
Thank you in advance.
Ok, so it seems I have fixed the issue by resolving the publicPath set in the file loader config field: publicPath: path.resolve(__dirname, '/assets/img').
My config is now:
"use strict";
const webpack = require('webpack');
const merge = require('webpack-merge');
const common = require('./webpack.common');
const path = require('path');
const ExtractCSSChunksPlugin = require('extract-css-chunks-webpack-plugin');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
entry: [
'webpack-hot-middleware/client',
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
}
}
},
{
test: /\.scss$/,
use: [
{
loader: ExtractCSSChunksPlugin.loader,
options: {
hot: true,
}
},
{
loader: 'css-loader',
options: {
sourceMap: true,
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
}
}
]
},
{
test: /\.html$/,
use:['html-loader']
},
{
test:/\.(svg|jpg|png|gif)$/,
use: [{
loader:'file-loader',
options: {
publicPath: path.resolve(__dirname, '/assets/img'),
outputPath: 'assets/img',
name: '[name].[ext]',
esModule: false
}
}],
},
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new ExtractCSSChunksPlugin({
filename: 'assets/css/[name].css',
chunkFilename: 'assets/css/[id].css',
}),
]
});
I think adding url loader in the webpack configuration would help.
{
test: /\.(jpg|png)$/,
use: {
loader: "url-loader",
options: {
limit: 25000,
},
},
},

Webpack: ignore references to svg/ttf files in css

I'm using webpack to export a css file. I'm using file-loader for svg/ttf files but it seems to copy them to the dist folder. Is there a way I can get webpack to just ignore referneces to svg/ttf in my css and leave as is? I've tried ignore-loader but it just replaces the file paths with [Object object].
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
performance: { hints: false },
mode: 'development',
devtool: 'source-map',
entry: ['babel-polyfill', './js/react-components/src/index.js'],
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'js/react-components/dist')
},
plugins: [
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// all options are optional
filename: 'output.css',
chunkFilename: 'chunk[id].css',
ignoreOrder: false, // Enable to remove warnings about conflicting order
}),
],
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|ttf|eot|svg|woff(2)?)(\?[a-z0-9-]+)?$/,
loader: 'file-loader'
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
resolve: {
extensions: [".js", ".jsx"]
},
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
use: [
{ loader: MiniCssExtractPlugin.loader,
options: {},
},
"css-loader"
]
}
]
}
};
I had a similar use case
Use esModule: false to fix the [Object object] in paths.
Also put all the assets in a /static/ folder (source is destination).
{
test: /\.(svg|png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
outputPath: '../static',
name: '[name].[ext]',
esModule: false
},
},
EDIT: Well that created a loop with npm run watch
I gave up and let the files be copied put the outputPath: './'
I also had to add an exception to CleanWebpackPlugin, or else they
plugins: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['!*.svg']
}), ...

Using Imports with .Net, React.Js, and Url.Content

I am using a .Net MVC framework, and trying to render a jsx (React) file that has imports. I am including this file in the razor page (cshtml) through the standard Url.Content injection as follows:
<script src="#Url.Content("~/js/queue/QueueIndex.js")"></script>
<script>
ReactDOM.render(React.createElement(QueueIndex), document.getElementById("queue-index"));
jQuery(window).on("load scroll", function () {
'use strict'; // Start of use strict
// Loader
$("#dvLoading").fadeOut("fast");
});
</script>
If I do not have an import at the top of my React file (QueueIndex.jsx) the page loads just fine. However, I would like to import the react-table package, but if include any imports in my QueueIndex.jsx file, the page breaks.
The error I'm getting is require is not defined.
I think the solution is somewhere in the use of webpack, here is my config:
const webpack = require("webpack");
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
nhqueue: './wwwroot/js/queue/QueueIndex.jsx'
},
output: {
path: __dirname + '/wwwroot/js/',
publicPath: '/wwwroot/js/',
filename: '[name].bundle.js'
},
module: {
preLoaders: [
],
loaders: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{ test: /\.tsx?$/, loaders: ['babel', 'ts'] },
{ test: /\.json$ /, loader: "json-loader" },
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: "babel",
query:
{
presets: ['react']
}
}
],
externals: {
"moment": "moment",
},
},
devtool: 'source-map',
target: 'web',
plugins: [
new CleanWebpackPlugin(['./wwwroot/js/*.js'], {
root: __dirname,
verbose: true,
dry: false
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin()
],
resolve: {
extensions: ['', '.jsx', '.js', '.tsx', '.ts']
},
node: {
fs: "empty",
child_process: "empty"
}
}
Unfortunately, I have had no luck there. Please let me know if you have any ideas of how to resolve this issue. Thanks!
Also, Here is the Babel configuration:
{"presets" : ["es2015", "react"]}

Categories

Resources