Webpack alliases work in browser, but not in node - node.js

To start off, this is my first post on stackoverflow so I hope I'm doing it right...
So my Webpack alliases work in browser, but not in node
I have a package (let's call it Services) with a subfolder dev and another project (let's call it MobX) which uses Services. In Mobx, I have a webpack configuration which is supposed, in development mode, change the paths of Services to have access to the subfolder dev instead.
Here's a sample of the code :
const devConfig = {
...commonConfig,
mode: "development",
devtool: "cheap-module-source-map",
entry: "./src/lib/index.ts",
output: {
path: outputDir,
library: name,
libraryTarget: "umd",
globalObject: "this",
},
optimization: {
minimize: false,
},
plugins: [...commonConfig.plugins, forkTsCheckerWebpackPlugin],
resolve: {
...commonConfig.resolve,
alias: {
"#intuition/services-apis$": "#intuition/services-apis/dev",
},
},
};
const devConfigNode = {
...devConfig,
target: ["node"],
name: "node",
output: {
...devConfig.output,
filename: splitChunks ? "[name].[contenthash].node.js" : "index.node.js",
},
};
const devConfigBrowser = {
...devConfig,
target: ["web", "es5"],
name: "browser",
output: {
...devConfig.output,
filename: splitChunks ? "[name].[contenthash].browser.js" : "index.browser.js",
},
};
I don't understand why, in node, it doesn't go into #intuition/services-apis/dev. In works fine in browser but no matter what I do, in node, it doesn't work. I have been at this day for days now and I can't seem to figure it out.
If my explanation wasn't clear enough and needs more details, please do not hesitate to ask any question.

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 :)

How to wrap Vite build in IIFE and still have all the dependencies bundled into a single file?

I'm building a chrome extension using Vite as my build tool. The main problem is during minification and mangling there are a lot of global variables created. After injecting my script to the page they conflict with already defined variables on window object.
I imagine the perfect solution would be to have my entire script wrapped in IIFE. I tried using esbuild.format = 'iife'. The resulting build is in fact wrapped in IIFE, however all the imports are not inlined. Instead resulting script is like 15 lines long with a bunch of require statements, which obviously does not work in the browser.
This is my config file:
export default defineConfig({
plugins: [
vue(),
],
esbuild: {
format: 'iife',
},
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, './src/web/index.ts'),
output: {
dir: resolve(__dirname, './dist'),
entryFileNames: 'web.js',
assetFileNames: 'style.css',
},
},
},
resolve: {
alias: {
'#': resolve(__dirname, './src'),
},
},
});
I'm currently using this hack so to say to wrap my build in IIFE (for this I removed the esbuild.format option).
Hey I am doing the exact same thing! And I also noticed the unminified variables and functions can clash with random code in a webpage.
From what I researched myself on this topic, you shouldn't change esbuild build options with Vite as that will prevent Rollup from transforming the output. Instead, you should use format: 'iife' in the rollupOptions of your vite.config. However, in my case (and yours I believe), I have to output multiple bundles since the extension code can't share modules amongst each other. Which will crash when you set the format to 'iife' due to:
Invalid value for option "output.inlineDynamicImports" - multiple inputs are not supported when "output.inlineDynamicImports" is true.
The only solution in my case seems to be to either use multiple vite.configs (I already have two) for each of my bundle with single input entry point and format as 'iife'. Or, as you did, just write the self-invoking function yourself with some hacky script. Seems though there aren't any perfect solutions as of now.
EDIT: Okay, got it working. This is my vite.config.ts (the project):
import { defineConfig } from 'vite'
import { svelte } from '#sveltejs/vite-plugin-svelte'
import tsconfigPaths from 'vite-tsconfig-paths'
import path from 'path'
/** #type {import('vite').UserConfig} */
export default defineConfig({
plugins: [svelte({}), tsconfigPaths()],
build: {
minify: false,
rollupOptions: {
output: {
chunkFileNames: '[name].js',
entryFileNames: '[name].js'
},
input: {
inject: path.resolve('./src/inject.ts'),
proxy: path.resolve('./src/proxy.ts'),
'pop-up': path.resolve('./pop-up.html')
},
plugins: [
{
name: 'wrap-in-iife',
generateBundle(outputOptions, bundle) {
Object.keys(bundle).forEach((fileName) => {
const file = bundle[fileName]
if (fileName.slice(-3) === '.js' && 'code' in file) {
file.code = `(() => {\n${file.code}})()`
}
})
}
}
]
}
}
})
Okay, I made it working with this config:
export default defineConfig({
plugins: [
vue(),
],
build: {
emptyOutDir: false,
rollupOptions: {
input: resolve(__dirname, './src/web/index.ts'),
output: {
format: 'iife',
dir: resolve(__dirname, './dist'),
entryFileNames: 'web.js',
assetFileNames: 'style.css',
},
},
},
resolve: {
alias: {
'#': resolve(__dirname, './src'),
},
},
});
They key part is format: 'iife' inside build.rollupOptions.output.

Cannot find module 'sanitize.css/page.css'

While building the gatsby project, I faced this kind of error.
yarn develop
ERROR #98123 WEBPACK
Generating development JavaScript bundle failed
Cannot find module 'sanitize.css/page.css'
Require stack:
- D:\UpworkJobs\Nate\dci-gatsby-importexport\node_modules\postcss-normalize\dist\index.cjs.js
File: src\css\preview.css
failed Building development bundle - 366.725s
Here is a screenshot of the error log.
These kinds of errors occur even if I removed all CSS codes from the style files.
It seems importing CSS files is not working. If I didn't import the CSS files, the errors go away.
Here are all codes of gatsby-config.js
let systemvars = false;
if (process.env.NODE_ENV === "production") {
systemvars = true;
}
require("dotenv").config({
path: `.env.${process.env.NODE_ENV}`,
systemvars
});
// Gatsby automatically sets NODE_ENV to `development` or `production` when running `gatsby develop` or `gatsby build`, respectively.
// Thus make sure you have .env.development or .env.production setup (unless your CI/build env vars are already set globally)
const AliasConfig = require("./alias.config.js");
module.exports = {
siteMetadata: {
title: `DCI DigiGuide Print`,
description: `DCI DigiGuide Printable Version`,
author: `#designbycosmic`,
siteUrl: process.env.SITE_URL,
},
plugins: [
//
// * App Functionality Plugins
//
// eslint plugin
{
resolve: "gatsby-plugin-eslint",
options: {
test: /\.js$|\.jsx$/,
exclude: /(node_modules|.cache|public)/,
stages: ["develop"],
options: {
maxWarnings: undefined,
emitWarning: true,
failOnError: false,
failOnWarning: false,
},
},
},
// allows content to be placed in head
`gatsby-plugin-react-helmet`,
// adds web manifest for some pwa functionality
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-dci-digiguide-print`,
short_name: `DigiGuidePrint`,
start_url: `/`,
background_color: `#222c47`,
theme_color: `#222c47`,
display: `minimal-ui`,
icon: `./src/images/favicon.png`, // This path is relative to the root of the site.
},
},
// allow alias imports
{
resolve: "gatsby-plugin-alias-imports",
options: {
alias: AliasConfig.map,
extensions: AliasConfig.extensions,
},
},
// inline svgs instead of converting them to base64
{
resolve: "gatsby-plugin-react-svg",
options: {
rule: {
include: /svg/,
},
},
},
`gatsby-plugin-postcss`,
`gatsby-plugin-material-ui`,
// Craft CMS configuration
{
resolve: `gatsby-source-graphql`,
options: {
url: process.env.CRAFT_API_URL,
typeName: "Craft",
fieldName: "craft",
headers: {
Authorization: `bearer ${process.env.CRAFT_API_TOKEN}`,
},
},
},
// Get build date
{
resolve: `gatsby-plugin-build-date`,
options: {
formatAsDateString: false,
},
},
],
};
Help me to solve this problem.
In my case I was able to solve by adding the following configuration in package.json.
"resolutions": {
"sanitize.css": "12.0.1"
},
Finally, this problem has been solved.
Using yarn instead of using npm solved the problem.
Remove node_modules and yarn install
After that, the problem has gone away.
Thank you.

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.

Why is Webpack 4 runtimeChunk in all entrypoints?

I am currently upgrading WP from v1.2 => v4.1 on a large commercial application. I am having an issue where splitChunks is creating multiple instances of my store for each entry point (The store we are using is extremely old and outdated, but that is out of my control ATM).
The issue as I see it is that runtime code is being added to each entry point which executes the same module multiple times - I succeeded in recreating the issue in a sandboxed environment and when I added a single runtimeChunk to my config this extracted the runtime code into a single file and resolved my issue - however when I applied this to my application - a runtime file WAS created, but runtimeChunk remained in each entrypoint also and so the problem still persists. Below is an example of my current config.
module.exports = {
entry: {
app: [
'babel-polyfill',
'whatwg-fetch',
'./src/app/app'
],
testEntry: './src/modules/testEntry.js',
},
output: {
pathinfo: true,
publicPath: '/',
chunkFilename: '[id].js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
]
},
optimization: {
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
filename: "js/[name].js",
test: /\.js(x)?$/,
chunks: "initial",
minChunks: 1
}
}
},
runtimeChunk: {
name: 'shared',
},
},
mode: 'development',
devtool: 'eval',
devServer: {
contentBase: __dirname,
port: 5000
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
};
Is another way I can force runtime code to be executed only once?
EDITED UPDATE
I have now updated to webpack 4.17 (latest) and now oddly - when I use the single runtime option - my entry bundles are not generated

Resources