How to use html-webpack-plugin with existing express templates? - html-webpack-plugin

I've intalled the express-generetor npm module and like how the project is structured with the jade files used as templates. However I also like to use the HTML-webpack-plugin which generates its own files, what is the best way to go about integrating both approaches?

Step1:
Generate your html file(s):
module.exports = {
entry: {
'page1': './apps/page1/scripts/main.js',
'page2': './apps/page2/src/main.js'
},
output: {
path: __dirname,
filename: "apps/[name]/build/bundle.js"
},
plugins: [
new HtmlWebpackPlugin({
inject: true,
chunks: ['page1'],
filename: 'apps/page1/build/index.html'
}),
new HtmlWebpackPlugin({
inject: true,
chunks: ['page2'],
filename: 'apps/page2/build/index.html'
})
]
};
Step2: Add the generated html file(s) to your jade file
include ../../public/index.html

Related

Webpack properly compiles, but updates not recognized from webpack-dev-server

I am trying to enable webpack-dev-server's hot-reload functionality on a multi-page site based at local.www.my-domain.com. The website is running locally inside a docker container.
The pages are written in php and rendered on Twig templates. Each page inherits from a master template, and each page's bundle is also conditionally rendered on this master template using a relative path (I do not inject anything from webpack itself). The bundles are loaded appropriately and run fine with this webpack config:
const path = require("path");
const TerserPlugin = require('terser-webpack-plugin');
const crawler = require('./crawlPaths.js');
const pages = crawler.getPaths('');
module.exports = {
mode: 'development',
entry: pages.reduce((config, page) => {
config[page.filePath + page.fileName] = `./js/${page.filePath + page.fileName}.${page.ext}`;
return config;
}, {}),
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../web/dist/bundles'),
library: {
type: 'umd',
},
},
devtool: 'inline-source-map',
optimization: {
splitChunks: {
chunks: 'all',
},
minimize: false,
minimizer: [
new TerserPlugin()
],
},
}
Note: I call a function called crawler.getPaths() in the config to retrieve pages that I want rendered; the page objects have this structure:
{
ext: 'js',
fileName: 'file',
filePath: '_snippets/',
templatePath: '_snippets/file.twig',
templateExt: 'twig'
}
However, I am having trouble introducing webpack-dev-server so that the pages update automatically. I tweaked the src attribute of the script tag that renders the bundle to instead point to a full path: http://local.www.my-domain-com:8080/web/dist/bundles/<name>.js.
Then I added a publicPath key to webpack's output object and added a devServer, watch, and watchOptions objects as well.
The bundles load appropriately when I visit http://local.www.my-domain-com:8080/web/dist/bundles/<name>.js. When the corresponding bundle is updated, webpack-dev-server does recompile. However, the recompiled page is not sent to http://local.www.my-domain-com:8080/web/dist/bundles/<name>.js; I need to hit refresh to see the update.
Furthermore, when I visit local.www.my-domain.com/path/, the corresponding :8080/web/dist/bundles/<name>.js bundle is visible and loaded in the 'Sources' tab of Chrome dev-tools, but the bundle is never run nor updated.
Here is the config I am using for the webpack-dev-server:
const path = require("path");
const TerserPlugin = require('terser-webpack-plugin');
const crawler = require('./crawlPaths.js');
const pages = crawler.getPaths('');
module.exports = {
mode: 'development',
entry: pages.reduce((config, page) => {
config[page.filePath + page.fileName] = `./js/${page.filePath + page.fileName}.${page.ext}`;
return config;
}, {}),
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, '../web/dist/bundles'),
library: {
type: 'umd',
},
publicPath: "http://local.www.my-domain-com:8080/web/dist/bundles",
},
devtool: 'inline-source-map',
optimization: {
splitChunks: {
chunks: 'all',
},
minimize: false,
minimizer: [
new TerserPlugin()
],
},
devServer: {
static: '../web/dist/bundles',
proxy: {
'/': {
target: "http://local.www.my-domain.com",
}
},
allowedHosts: ".my-domain.com",
host: '0.0.0.0',
hot: true,
},
watchOptions: {
aggregateTimeout: 300,
poll: 1000,
ignored: /node_modules/,
},
watch: true,
}
The webpack-dev-server is a proxy for the website's Nginx server, which is running inside a docker container.
Any ideas what I need to do to get this running? And please let me know if I can provide anymore information :)

include a config file in webpack bundle

In my webpack project I want to bundle my project and include an example usage file with it. However when I bundle my project in this form
module.exports = {
entry: {
main: './src/main.js',
about: './src/pages/config.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'report' //makes this a global variable we can call from basic javascript page,
devtool: 'source-map',
devServer: {
port: 3001,
clientLogLevel: 'none',
stats: 'errors-only'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] //npm install --save-dev style-loader css-loader
}
]
},
plugins: [
new CleanWebpackPlugin({ cleanStaleWebpackAssets: false }),
new HtmlWebpackPlugin({
title: 'ESS Map Learning',
}),
],
};
},
The outputted file in the dist is converted or loaded into bundled code and is unreadable as an example. I am trying to find a way to load this file so it is not changed and sits in the bundle in its original format
If you want to include an example usage file along with your bundle, you can try the following two ways:
1. use CopyWebpackPlugin
With this plugin, you can copy specific files from your source project into your output folder.
First you need to install the plugin:
npm install --save-dev copy-webpack-plugin
Then in your webpack configuration file:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin([
{
from: "path/to/some-example.js",
to: "" // leave blank if you want to keep the folder hierachy as in the source code, otherwise specify an output path
},
]),
]
}
More about the plugin:
Webpack Plugins: CopyWebpackPlugin
2. use the "Asset Modules" configuration
module.exports = {
module: {
rules: [
{
test: /example\.js/, // regex to match your source example file path
type: 'asset/resource', // files with this type will be copied to your output folder
generator: {
filename: 'examples/[name][ext]', // you can give a desired name for your output file, or webpack will defaultly name it with hash value
}
}
]
},
// rest of your webpack configuration
// ...
}
Caveats: I think webpack will never process your example file if it is not a dependency of any of your entry points (which is very likely the case). In this sense I guess using the CopyWebpackPlugin is more reliable.
More about asset modules:
Webpack Guides: Asset Management
Webpack Guides: Asset Modules

how to use `dependOn` to bundle separate application files from the main entry point?

I have a backend project that I would like to bundle using Webpack v5.
I would like to split some of the files into their own bundles and have them imported into the main entry.
The main entry has a dependOn key that contains an array of filenames that will be used by the main entry.
This is the webpack.config.json:
module.exports = {
entry: {
app: {
import: './index.ts',
dependOn: 'routes'
},
routes: ['./routes.ts']
},
output: {
filename: '[name].js',
libraryTarget: 'commonjs2',
path: path.resolve(__dirname, 'build')
},
resolve: {
extensions: ['.ts', '.js']
},
target: 'node',
externals: [
nodeExternals()
],
mode: 'production',
optimization: {
minimize: false,
},
module: {
rules: [{ test: /\.tsx?$/, loader: 'ts-loader' }]
},
plugins: [
new ContextReplacementPlugin(/any-promise/)
]
};
After running the build two files are generated (app.js & routes.js) as expected. But when running the entry point with NodeJS I get the following error: webpack_require.C does not exist.
Going through the documentation I see that their example dependOn is based on packages and not indvidual application files.
Can you add applicaton files to dependOn? Does this have something to do with module resolution?
Let me assume you have imported the routes in your app, and you want to split routes into a separate bundle instead of being included in the bundled app.js.
Here's how you could make it with SplitChunksPlugin https://webpack.js.org/plugins/split-chunks-plugin.
module.exports = {
entry: {
app: "./index"
},
target: "node",
optimization: {
splitChunks: {
cacheGroups: {
routes: {
filename: "routes.js",
test: module => {
return module.resource && module.resource.includes("routes");
},
enforce: true,
chunks: "all"
}
}
}
}
};
Webpack will output two files, app.js and routes.js.

Entrypoint undefined = index.html using HtmlWebpackPlugin

I'm using Webpack 4 and I'm creating the config file, when trying to use the HtmlWebpackPlugin it got this on the console: Entrypoint undefined = index.html, it opens the browser and the HTML does appear but I'm getting this weird message on the console, how to solve this?
That is how my config file looks like:
'use strict'
const webpack = require('webpack')
const { join, resolve } = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development', // dev
devtool: 'cheap-module-eval-source-map', // dev
entry: join(__dirname, 'src', 'index.js'),
output: {
filename: 'bundle.js',
path: resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
devServer: {
contentBase: resolve(__dirname, 'build')
},
plugins: [
new webpack.ProgressPlugin(),
new HtmlWebpackPlugin({
template: join(__dirname, 'public', 'index.html')
}),
new webpack.HotModuleReplacementPlugin(), // dev
new webpack.NoEmitOnErrorsPlugin() // dev
]
}
Try this; you might be making wrong template path :
new HtmlWebpackPlugin({
template: resolve(__dirname, 'src/public', 'index.html'),
filename: './index.html'
}),
If public is in src folder this should work It's my assumption.
Let me know if the issue still persists.
According to the creators of HtmlWebpackPlugin it's just a meaningless log message and an ignorable cosmetic issue. See this comment on the issue.
It seems like a problem with the extension of the template firing an unwanted loader. If the extension of the template is changed to any other the plugin will work.
If you're using the default webpack template system (EJS, as of webpack 4) it makes sense to use ejs because the template isn't valid html anymore:
new HtmlWebpackPlugin({
// it works without 'path.resolve()'. No need for 'filename', defaults to 'index.html'
template: "./public/index.ejs",
}),
webpack considers by default that the template is EJS and will automatically process it with the proper loader. If you use any other template system you will have to add the corresponding loader. More info on official documentation.
plugins: [
...
new HtmlWebPackPlugin({
title: '...',
template: path.resolve(folderSrc, 'index.html'),
filename: 'index.html',
hash: true
})
]
Error got fixed in mine by adding this in webpack.config.js :
stats: { children: false }, //to fix the error-Entrypoint undefined=index.html
plugins:[
new HtmlWebpackPlugin({
template: './index.html'
})
]

Compiling two files with RequireJS Optimize

I am trying to specify compilation for two files in the build.js file for RequireJS optimizer. But only the last file gets optimized. Here's the build.js file:
({
baseUrl: "..",
name: "client/TestA",
out: "full.js",
findNestedDependencies: true
},{
baseUrl: "..",
name: "client/TestB",
out: "fullB.js",
findNestedDependencies: true
})
In this case only the last entry client/TestB is getting built. I need the require Optimizer to build both.
Where did you found this format of build.js file? Maybe you need something like modules field?
It should be something like this:
({
baseUrl: "..",
dir : './out' // required when using modules, instead 'out' field
modules: [
{
name: "client/TestA"
},
{
name: "client/TestB"
}
],
findNestedDependencies: true
});

Resources