HtmlWebpackPlugin ignores filename - javascript

I'm trying out code/bundle splitting with webpack, however I ran in to an issue. HTMLWebpackPlugin is as far as I know supposed to dynamically insert script tags into an HTML file. This HTML file is by default index.html and it seems to work when I use the default. Because I use .NET with a _Layout.cshtml and Index.cshtml, it would like it to use the Index.cshtml.
HTMLWebpackPlugin seems to completely ignore what is in "filename", and generates an index.html:
new HtmlWebpackPlugin({
template: '../../Views/Shared/_Layout.cshtml',
filename: 'test-index.html' // Generates index.html, not test-index.html...
//filename: '../Views/Home/Index.cshtml' // Not working either. Generates index.html
})
webpack.common.js:
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var helpers = require('./helpers');
module.exports = {
entry: {
'polyfills': './ClientApp/polyfills.ts',
'vendor': './ClientApp/vendor.ts',
'app': './ClientApp/main.ts'
},
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.ts$/,
loaders: [
{
loader: 'awesome-typescript-loader',
options: { configFileName: helpers.root('ClientApp', 'tsconfig.json') }
} , 'angular2-template-loader'
]
},
{
test: /\.html$/,
use: ['raw-loader']
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=assets/[name].[hash].[ext]'
},
{
test: /\.css$/,
include: helpers.root('ClientApp', 'app'),
use: ['to-string-loader', 'css-loader']
}
]
},
optimization:
{
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: Infinity,
minSize: 0,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name(module) {
// get the name. E.g. node_modules/packageName/not/this/part.js
// or node_modules/packageName
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
// npm package names are URL-safe, but some servers don't like # symbols
return `npm.${packageName.replace('#', '')}`;
},
},
}
}
},
plugins: [
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)(#angular|fesm5)/,
helpers.root('ClientApp'),
{}
),
new webpack.BannerPlugin('© COPYRIGHT LIGHTHOUSE INTELLIGENCE ' + new Date().getFullYear()),
new HtmlWebpackPlugin({
template: '../../Views/Shared/_Layout.cshtml',
filename: 'test-index.html' // Generates index.html, not test-index.html...
//filename: '../Views/Home/Index.cshtml' // Not working either
})
]
};
webpack.dev.js:
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var helpers = require('./helpers');
module.exports = webpackMerge(commonConfig, {
devtool: 'cheap-module-eval-source-map',
mode: "development",
output: {
path: helpers.root('/wwwroot/dist'),
publicPath: '/wwwroot/dist/',
filename: '[name].js', //.[hash]
chunkFilename: '[id].js' //.chunk
},
plugins: [
new ExtractTextPlugin('[name].css'),
],
devServer: {
historyApiFallback: true,
stats: 'minimal'
}
});

I dont think you cant do that. Razor cshtml file need to have everything include in the view before you build and run your project so that it can build and transform cshtml to html.
htmlwebpackplugin only work with html so the only option you can choose is serve the html file in your .net core project

Location of the output file is determined by the output attribute of webpack.config.js (path: helpers.root('/wwwroot/dist')). So you have to specify only the file name for the filename attribute.

Related

Webpack multiple entries under certain urls

Hey I have this project which has this structure:
bundler -> webpack.common.js
src -> main.js, index.html, styles.css
package.json
node_modules... the rest doesnt matter really
It is set up like when I do: npm run dev webpack creates a live server using my current main.js for my index.html
The webpack.common.js looks like this:
const CopyWebpackPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCSSExtractPlugin = require("mini-css-extract-plugin");
const path = require("path");
module.exports = {
entry: path.resolve(__dirname, "../src/current_script.js"),
output: {
hashFunction: "xxhash64",
filename: "bundle.[contenthash].js",
path: path.resolve(__dirname, "../dist"),
},
devtool: "source-map",
plugins: [
new CopyWebpackPlugin({
patterns: [{ from: path.resolve(__dirname, "../static") }],
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "../src/index.html"),
minify: true,
}),
new MiniCSSExtractPlugin(),
],
module: {
rules: [
// HTML
{
test: /\.(html)$/,
use: ["html-loader"],
},
// JS
{
test: /\.js$/,
exclude: /node_modules/,
use: ["babel-loader"],
},
// CSS
{
test: /\.css$/,
use: [MiniCSSExtractPlugin.loader, "css-loader"],
},
// Images
{
test: /\.(jpg|png|gif|svg)$/,
type: "asset/resource",
generator: {
filename: "assets/images/[hash][ext]",
},
},
// Fonts
{
test: /\.(ttf|eot|woff|woff2)$/,
type: "asset/resource",
generator: {
filename: "assets/fonts/[hash][ext]",
},
},
],
},
};
```
Now my question is how can I define multiple entries under certain URLs.
So for example now under localhost/ it will redirect me to index.html using my main.js
Is there a way of having localhost/2 use my index.html with another js file like main2.js

Font urls path is wrong and includes css path after WebPack Build

I can't figure out the right combo here to make this all happy. I'm having MiniCssExtractPlugin create css or less files encountered.
I am importing a less and a css file in src/client/index.tsx:
import './less/master.less';
import '../../ext/ink-3.1.10/css/ink.min.css';
webpack.config.js is then doing its magic with MiniCssExtractPlugin:
Note: the reasons I have publicPath: '' for the css loader is because when I had it as publicPath: '/lib/css', it was appending that to the font url so by removing that the font-urls no longer had the issue at least after webpack created dist of the underlying problem I still see at runtime. Honestly I don't know if I even need to set publicPath here anyway because it defaults to "" anyway.
Changing it then to publicPath: '', stripped out the /lib/css part from /lib/css/lib/assets/fonts and I thought that fixed my issue but then during runtime it's still trying to hit fonts via /lib/css/lib/assets/fonts which baffles me
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const html = () => {
return new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
};
const copyAllOtherDistFiles = () => {
return new CopyPlugin({
patterns: [
{ from: 'src/client/assets', to: 'lib/assets' },
{ from: 'package.json', to: './' },
{ from: 'ext/ink-3.1.10/js/ink-all.min.js', to: 'lib/js' },
{ from: 'ext/ink-3.1.10/js/autoload.min.js', to: 'lib/js' },
{ from: 'ext/js/jquery-2.2.3.min.js', to: 'lib/js' },
{ from: 'feed.xml', to: './' },
{
from: 'src/shared',
to: './shared',
globOptions: {
ignore: ['**/*suppressed.json'],
},
},
],
});
};
module.exports = {
entry: './src/client/index.tsx',
output: {
filename: 'scripts/app.[hash].bundle.js',
publicPath: '',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
devtool: isProduction ? '' : 'eval-cheap-source-map',
devServer: {
writeToDisk: true,
contentBase: path.resolve(__dirname, 'dist'),
port: 8080,
},
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.(tsx|ts)?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '',
},
},
'css-loader',
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: 'lib/assets/fonts',
},
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['url-loader'],
},
],
},
plugins: [
new CleanWebpackPlugin(),
copyAllOtherDistFiles(),
new MiniCssExtractPlugin({
filename: isProduction ? 'lib/css/[name].[hash].css' : 'lib/css/main.css',
}),
html(),
],
};
api.js
const compression = require('compression'),
express = require('express'),
historyApi = require('connect-history-api-fallback'),
oneYear = 31536000;
module.exports = express()
.use(compression())
.on('error', (err: string) => {
console.log(err);
})
.use(historyApi())
.use(
express.static('dist', {
maxage: oneYear,
})
)
.use((_req: any, res: any) => {
res.send('Sorry, Page Not Found');
});
So the issue comes up during runtime with ink.min.css because it's referencing some fonts that I also processed with file-loader as you can see above. The problem is when I run the site in Dev mode via NODE_ENV=development webpack-dev-server --open I end up with a few requests for those fonts because it's appending /lib/css/lib/assets/fonts instead of just /lib/assets/fonts during runtime:
The weird thing about this though is when I go to my dist folder, when I look at styles.main.css (which apparently it renamed ink.min.css to this for some odd reason, the url to the fonts don't have that extra /lib/css so I don't understand why when my browser loads it's trying to reference it with that extra part still:
Another thing that's kinda weird is I do see images loading but when I look at the source in the browser, I don't see my assets folder. I know dist definitely contains it, but it doesn't show it here:
I don't understand why this fixed it. This entire thing feels hacky to me.
I changed it to publicPath: '../../'
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../../',
},
},
'css-loader',
],
I guess I'm loading my .css file and then I'm under the context of /lib/css already so my font urls have /lib/css I guess? and I need to for some reason have MiniCssExtractPlugin have a public path at the root? I don't get it.
Also now I see the assets folder, wt???

How to dynamically load an asset (pdf) in an angular app using webpack?

I am trying to load a pdf into my angular app running on webpack dev server using HTML <object> tag with data attribute.
Since the pdf path is generated at run time and is absolute like C:\test.pdf.
It is not loaded into the UI but rather console logs the error -
Not allowed to load local resource: file:///C:/test.jpeg
However the production build of the app which doesn't run on hosting server but as static html works fine. Also, relative path works fine as well.
How can i load the pdf ?
webpack.common.js
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const rootDir = path.resolve(__dirname, '..');
module.exports = {
resolve: {
extensions: ['.js', '.ts'],
modules: [rootDir, path.join(rootDir, "node_modules")]
},
module: {
rules: [
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=assets/[name].[ext]'
},
{
test: /\.(scss|css)$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "sass-loader",
options: {
includePaths: ["node_modules/"]
}
}
]
}
]},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['app', 'vendor', 'polyfills']
}),
new HtmlWebpackPlugin({
template: 'src/index.html'
}),
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)#angular/,
path.resolve(__dirname, '../src')
)
]
};
webpack.dev.js
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var commonConfig = require('./webpack.common.js');
const path = require('path');
const rootDir = path.resolve(__dirname, '..');
commonConfig.entry = {
'polyfills': './src/polyfills.ts',
'vendor': './src/vendor.ts',
'app': './src/main.ts'
};
commonConfig.module.rules.unshift({
test: /\.ts$/,
loaders: ['awesome-typescript-loader', 'angular2-template-loader', 'angular-router-loader']
});
module.exports = webpackMerge(commonConfig, {
devtool: 'cheap-module-eval-source-map',
output: {
path: path.resolve(rootDir, 'dist'),
publicPath: 'http://localhost:8080/',
filename: '[name].js',
chunkFilename: '[name].chunk.js'
},
plugins: [
new ExtractTextPlugin('[name].css')
],
devServer: {
historyApiFallback: true,
stats: 'minimal'
}
});
You could tell the devServer from where to serve files.
devServer: {
historyApiFallback: true,
stats: 'minimal',
contentBase: ['./dist', 'C:\\']
}
Then you can load your file with <... src="/file_name.ext" ... />
But I would not recommend adding C:\ as contentBase. If you have the possiblity, define another output directory for your generated PDF.

push assets folder to public directory with webpack

I'm using Webpack for the first time. Currently everything is being served up quite nicely. My problem is when I'm trying to build a dist folder. Currently I get my index.html and bundle.js files but I can't figure out how to push my assets to the dist folder.
I have file-loader loaded up but it doesn't actually seem to do what I want it to and none of the google searches I've run are telling me what I need to know. Below is my config file. Can someone lead a horse to water? Also once I get it running do I need to import all of images to my React components?
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/'
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{ test: /\.scss$/, use: [ 'style-loader', 'css-loader', 'sass-loader' ]},
{ test: /\.(png|jpe?g|svg|)$/, use: { loader: 'file-loader', options: }}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'app/index.html'
})
]
};
Looks like I just needed to use Copy-Webpack-Plugin.
To copy all the assets from 'app/assets/' to 'dist/assets/' I just needed to do:
plugins: [
new CopyWebpackPlugin([
{ from: 'app/assets', to: 'assets' }
])
]
First install copy webpack plugin:
npm i copy-webpack-plugin
Then in the webpack.config.json:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "src/public", to: "" } //to the dist root directory
],
}),
],
};

Make Webpack render in a file other than an index

By default Webpack looks for a specific index.html file in a specified directory, right? What I want to know is can I tell webpack to look for and inject my bundled files in a file that I specify?
I ask this because I'm trying to develop a Ghost theme with webpack and by default, a Ghost theme looks for a default.hbs file to serve as an index file.
I tried to use the HtmlWebpackPlugin to set the filename for entry all while making the same file for web pack's output, but it's not working.
This is my current webpack.dev.config.js:
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:2368',
'webpack/hot/only-dev-server',
'./src/router'
],
devtool: 'eval',
debug: true,
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
publicPath: '/static/'
},
resolveLoader: {
modulesDirectories: ['node_modules']
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new HtmlWebpackPlugin({
hash: true,
filename: 'default.hbs',
template: __dirname + '/public/default.hbs',
})
],
resolve: {
extensions: ['', '.js', '.sass', '.css', '.hbs']
},
module: {
loaders: [
// js
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel'],
include: path.join(__dirname, 'src')
},
// CSS
{
test: /\.sass$/,
include: path.join(__dirname, 'src'),
loader: 'style-loader!css-loader!sass-loader'
},
// handlebars
{
test: /\.hbs$/,
include: path.join(__dirname, 'public'),
loader: 'handlebars-template-loader'
}
]
},
node: {
fs: 'empty'
}
};
Easiest way: you can configure webpack to use any file and template file via the html-webpack-plugin plugin. You can also specify the element to inject into.
import HtmlWebpackPlugin from 'html-webpack-plugin';
[...]
const plugins = [
new HtmlWebpackPlugin({
template: 'templates/myTemplateFile.tpl.html',
inject: 'body',
filename: 'myOutputFile.html'
})
];

Categories

Resources