Override what's bundled in webpack based on file extension - javascript

I'm trying to figure out whether or not webpack can do something like this. I have some code that I want to be bundled for a specific device. So I created a ViewFactories.ios.tsx and I also have ViewFactories.tsx. The problem i'm encountering is that the if I ignore the .ios.tsx in the loader test, it still gets bundled. I'm using the ignore-bundler plugin to ignore the .ios.tsx files, but the reference is just empty. ie:
/** still getting loaded here: **/
const ViewFactories_ios_1 = __importDefault(__webpack_require__(/*! ./ViewFactories.ios */ "./build/app/src/modules/layouts/factories/ViewFactories.ios.tsx"));
/*** the referenced section, but blank now ***/
/***/ "./build/app/src/modules/layouts/factories/ViewFactories.ios.tsx":
/*!***********************************************************************!*\
!*** ./build/app/src/modules/layouts/factories/ViewFactories.ios.tsx ***!
\***********************************************************************/
/*! dynamic exports provided */
/*! all exports used */
/***/ (function(module, exports) {
/***/ }),
What I really want is the reference to ViewFactories.tsx instead of ViewFactories.ios.tsx.
Is there some sort of dependency graph in webpack that I can access to tell the loader to use the default instead of the .ios.tsx?
My webpack config:
{
test: (modulePath) => {
if (/\.ios\./.test(modulePath)) {
console.log(modulePath);
return false;
}
return /\.tsx?$/.test(modulePath);
},
loader: "awesome-typescript-loader",
options: {
configFileName: 'tsconfig.web.json',
transpileOnly: true,
errorsAsWarnings: true,
}
},
{
test: (modulePath) => {
if (/\.ios\./.test(modulePath)) {
console.log('Ignored: ', modulePath);
return true;
}
return false;
},
loader: 'ignore-loader'
},

Just build two bundles, with shared config options for whatever is the same?
// webpack.config.js for two different bundles
let sharedModuleDef = {
rules: ...
}
let sharedPlugins = ...
let iosBundle = {
entry: "src/ios.entry.js",
output: {
path: ...
filename: "ios.bundle.js"
},
module: sharedModuleDef,
...
};
let everythingElse = {
entry: "src/main.entry.js",
output: {
path: ...
filename: "standard.bundle.js"
},
module: sharedModuleDef,
...
};
module.exports = [iosBundle, everythingElse];

Related

Option to get a single line main.js output with only references (webpack)?

I'm new to webpack and I have been put on a project where someone was already coding something before me. I have all the source code and I have also a webpack.config.js file.
I want to rebuild the output main.js from those files but I think I might be missing some steps to get there. I use the loader babel by the way and the react library.
When I run npx webpack in the folder where the .config.js file is I have something with this structure:
/*! For license information please see main.js.LICENSE.txt */
(() => {
var e = {
418: e => {
"use strict";
var t = Object.getOwnPropertySymbols,
n = Object.prototype.hasOwnProperty,
r = Object.prototype.propertyIsEnumerable;
function o(e) {...
I want to get something that looks like this (I modified it so it is more readable but normally everything is on one line):
() => {
var __webpack_modules__ = {
"./src/components/app.js": (__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
If anyone has an idea feel free to tell me, I just started using webpack two weeks ago and I might have misunderstood something.
My Webpack.config.js file
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./static/frontend"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
},
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
],
},
optimization: {
minimize: true,
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
// This has effect on the react lib size
NODE_ENV: JSON.stringify("production"),
},
}),
new HtmlWebpackPlugin({
favicon: "./src/small-logo-orange.svg"
}),
],
};
Ok after some research I found out what was my problem.
The previous guy gave me a webpack.config.js file with no option for the mode field in :
module.exports = {
};
To get the same thing as him I need to have the mode set to 'development'
module.exports = {
mode: 'development', ...
};
See https://webpack.js.org/configuration/mode
Hope this will help someone one day.

Webpack-compiled CSS file is including Javascript variables and functions

We use a simple application of webpack/mix:
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/cpg.js', 'public/js')
.js('resources/js/editor.js', 'public/js')
.copy('resources/js/ckeditor/dist', 'public/js/editor')
.sass('resources/sass/app.scss', 'public/css')
.sass('resources/sass/cpg.scss', 'public/css')
With webpack.config.js:
module.exports = {
resolve: {
alias: {
'#': path.resolve('resources/js'),
},
},
// https://webpack.js.org/configuration/entry-context/
entry: './resources/js/editor.js',
// https://webpack.js.org/configuration/output/
output: {
path: path.resolve(__dirname, 'public/js/editor'),
filename: 'editor.js'
},
module: {
rules: [
{
test: /ckeditor5-[^/\\]+[/\\]theme[/\\]icons[/\\][^/\\]+\.svg$/,
use: ['raw-loader']
},
{
test: /ckeditor5-[^/\\]+[/\\]theme[/\\].+\.css$/,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag',
attributes: {
'data-cke': true
}
}
},
{
loader: 'postcss-loader',
options: styles.getPostCssConfig({
themeImporter: {
themePath: require.resolve('#ckeditor/ckeditor5-theme-lark')
},
minify: true
})
}
]
}
]
},
// Useful for debugging.
devtool: 'source-map',
// By default webpack logs warnings if the bundle is bigger than 200kb.
performance: { hints: false }
}
Prior to the addition of ckeditor, we had no troubles. But now that ckeditor has been added, the following JS now appears in our compiled cpg.css file:
function webpackContext(req) {
var id = webpackContextResolve(req);
return __webpack_require__(id);
}
function webpackContextResolve(req) {
if(!__webpack_require__.o(map, req)) {
var e = new Error("Cannot find module '" + req + "'");
e.code = 'MODULE_NOT_FOUND';
throw e;
}
return map[req];
}
webpackContext.keys = function webpackContextKeys() {
return Object.keys(map);
};
webpackContext.resolve = webpackContextResolve;
module.exports = webpackContext;
webpackContext.id = "./node_modules/moment/locale sync recursive ^\\.\\/.*$";
Obviously, this is a problem. JS code does not belong in CSS files, and it trips up our SonarCloud quality gate (for good reason) so we can't deploy anything that's been compiled unless we manually edit the compiled files. Which mostly defeats the purpose of having them.
Further backstory: the section of our project that uses CKEditor was completed by a contractor. So, all of this was merged into our project before we saw that compiled files were improper. The contractor is no longer with the company, so I'm trying to debug on my own and getting nowhere. It seems to be an exceedingly rare bug for Webpack to place JS code in a CSS file.
Progress update: Removing the ckeditor references has no impact. The Webpack just seems to be broken now. Comprehensive node_modules re-install had no effect. It's just broken.
Issue appears to be a copy of https://github.com/laravel-mix/laravel-mix/issues/1976. Upgrading to Mix 6 creates an absolutely absurd amount of problems for my project, so this will just go unresolved.
Followed the instructions here: https://github.com/laravel-mix/laravel-mix/issues/2633#issuecomment-802023077 I was able to resolve the problem.
Might be related to this https://github.com/ckeditor/ckeditor5/issues/8112
A solution there suggests this change
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag',
attributes: {
'data-cke': true
}
}
},
'css-loader', // added this line
{
loader: 'postcss-loader',
options: styles.getPostCssConfig({
themeImporter: {
themePath: require.resolve('#ckeditor/ckeditor5-theme-lark')
},
minify: true
})
}
]

Webpack problem generating sourcemaps -- only generated when a particular plugin is disabled

I'm using my own custom plugin to strip some optional code from a build. This works well, but for some reason it seems to be blocking generation of source maps.
My best guess is that the fact that I'm modifying the index.js output file interferes with the ability to generate a map of for that file. If I comment out the plugin, my source maps come back.
Is there perhaps something I can do to change order of plugin execution that will fix this? Or perhaps a way to strip code from source file input streams (not from the files themselves) rather than from the generated output?
I've tried explicitly adding SourceMapDevToolPlugin to my plugins, but that didn't help.
Here's my webpack.config.cjs file:
const { Compilation, sources } = require('webpack');
const { resolve } = require('path');
module.exports = env => {
const esVersion = env?.esver === '5' ? 'es5' : 'es6';
const dir = env?.esver === '5' ? 'web5' : 'web';
const chromeVersion = env?.esver === '5' ? '23' : '51';
// noinspection JSUnresolvedVariable,JSUnresolvedFunction,JSUnresolvedFunction
return {
mode: env?.dev ? 'development' : 'production',
target: [esVersion, 'web'],
entry: {
index: './dist/index.js'
},
output: {
path: resolve(__dirname, 'dist/' + dir),
filename: `index.js`,
libraryTarget: 'umd',
library: 'tbTime'
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: { presets: [['#babel/preset-env', { targets: { chrome: chromeVersion } }]] }
},
resolve: { fullySpecified: false }
}
]
},
resolve: {
mainFields: ['esm2015', 'es2015', 'module', 'main', 'browser']
},
externals: { 'by-request': 'by-request' },
devtool: 'source-map',
plugins: [
new class OutputMonitor {
// noinspection JSUnusedGlobalSymbols
apply(compiler) {
compiler.hooks.thisCompilation.tap('OutputMonitor', (compilation) => {
compilation.hooks.processAssets.tap(
{ name: 'OutputMonitor', stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE },
() => {
const file = compilation.getAsset('index.js');
let contents = file.source.source();
// Strip out dynamic import() so it doesn't generate warnings.
contents = contents.replace(/return import\(.*?\/\* webpackIgnore: true \*\/.*?tseuqer-yb.*?\.join\(''\)\)/s, 'return null');
// Strip out large and large-alt timezone definitions from this build.
contents = contents.replace(/\/\* trim-file-start \*\/.*?\/\* trim-file-end \*\//sg, 'null');
compilation.updateAsset('index.js', new sources.RawSource(contents));
}
);
});
}
}()
]
};
};
Full project source can be found here: https://github.com/kshetline/tubular_time/tree/development
I think using RawSource would disable the source map. The right one for devtool is supposed to be SourceMapSource so the idea looks like following:
const file = compilation.getAsset('index.js');
const {devtool} = compiler.options;
let contents = file.source.source();
const {map} = file.source.sourceAndMap();
// your replace work
// ...
compilation.updateAsset(
'index.js',
devtool
// for devtool we have to pass map file but this the original one
// it would be wrong since you have already changed the content
? new sources.SourceMapSource(contents, 'index.js', map)
: new sources.RawSource(contents)
);

Vue Cli 3 is not allowing me to process SVG's in Webpack

Vue Cli defaults to file-loader for SVG assets, but I want to use svg-sprite-loader (as well as a few others) instead.
I updated the vue.config.js file to do this and it still seems to use file-loader. Almost as though it's not picking up my config at all.
vue.config.js
module.exports = {
configureWebpack: {
module: {
rules: [
{
test: /\.(svg)(\?.*)?$/,
use: [
{
loader: 'svg-sprite-loader',
options: {
name: '[name]-[hash:7]',
prefixize: true
}
},
'svg-fill-loader',
'svgo-loader'
]
}
]
}
}
}
Is there anything wrong with my setup?
I'm still getting SVG files imported into my component as a URL string / path when it should be an object with properties.
Many thanks.
This took me a while to find a work around. Basically you need to stop file-loader matching on .svg. The best way I have found to do this is using chainWebpack and returning false from the test method on file-loader. I have included my working config.
module.exports = {
lintOnSave: false,
configureWebpack: {
module: {
rules: [
{
test: /\.(svg)(\?.*)?$/,
use: [
{
loader: 'svg-inline-loader',
options: {
limit: 10000,
name: 'assets/img/[name].[hash:7].[ext]'
}
}
]
}
]
}
},
chainWebpack: config => {
config.module
.rule('svg')
.test(() => false)
.use('file-loader')
}
}
The Webpack docs for Vue CLI 3.0 beta got updated with an example on how to replace an existing Base Loader. For svg-sprite-loader this means that you'll have to add the following configuration to your vue.config.js:
chainWebpack: config => {
config.module
.rule('svg')
.use('file-loader')
.loader('svg-sprite-loader')
}
I'm using Vue CLI 3.0.3 and this config works for me 😉
const path = require('path');
const glob = require('glob');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
module.exports = {
lintOnSave: false,
configureWebpack: {
plugins: [
new SpriteLoaderPlugin()
]
},
chainWebpack: config => {
config.module.rules.delete('svg');
config
.entry('app')
.clear()
.add(path.resolve(__dirname, './src/main.ts'))
config
.entry('sprite')
.add(...glob.sync(path.resolve(__dirname, `./src/assets/icons/*.svg`)));
config.module.rule('svg')
.test(/\.(svg)(\?.*)?$/)
.use('file-loader')
.loader('svg-sprite-loader')
.options({
extract: true,
spriteFilename: 'icons.svg'
})
}
};
Vue CLI docs for version 3.x in webpack section suggests to use something like this:
// vue.config.js
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
// clear all existing loaders.
// if you don't do this, the loader below will be appended to
// existing loaders of the rule.
svgRule.uses.clear()
// add replacement loader(s)
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
}
Even vue-svg-loader configuration guide suggests same approach.
module.exports = {
chainWebpack: config => {
const svgRule = config.module.rule('svg')
svgRule.clear()
svgRule
.use('vue-svg-loader')
.loader('vue-svg-loader')
}
}

Local JavaScript Files Not Updating - Stencil CLI

I am modifying a purchased stencil-based theme for a client. When I modify javascript files, bundle.js does not update and I do not see a file change in the CLI. I am unable to see my changes on the local site. However, as a test, I was able to modify bundle.js directly and saw my change take place.
I have looked through the BC docs and have asked questions in other forums, but still no solution. I am not getting any errors in the CLI when I start stencil or run the bundle command. I can also upload my theme to the store without error.
Any ideas?
**Edit:
Here are the contents of my stencil.conf.js file:
var path = require('path');
var webpack = require('webpack');
var webpackConfig = require('./webpack.conf.js');
webpackConfig.context = __dirname;
webpackConfig.entry = path.resolve(__dirname, 'assets/js/app.js');
webpackConfig.output = {
path: path.resolve(__dirname, 'assets/js'),
filename: 'bundle.js'
};
/**
* Watch options for the core watcher
* #type {{files: string[], ignored: string[]}}
*/
var watchOptions = {
// If files in these directories change, reload the page.
files: [
'/assets',
'/templates',
'/lang'
],
//Do not watch files in these directories
ignored: [
'/assets/scss',
'/assets/css',
]
};
/**
* Hook into the stencil-cli browsersync instance for rapid development of themes.
* Watch any custom files and trigger a rebuild
* #param {Object} Bs
*/
function development(Bs) {
var compiler = webpack(webpackConfig);
// Rebuild the bundle once at bootup
compiler.watch({}, function(err, stats) {
if (err) {
console.error(err)
}
Bs.reload();
});
}
/**
*/
/**
* Hook into the `stencil bundle` command and build your files before they are packaged as a .zip
* Be sure to call the `done()` callback when finished
* #param {function} done
*/
function production(done) {
var compiler;
webpackConfig.devtool = false;
webpackConfig.plugins.push(new webpack.optimize.DedupePlugin());
webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
comments: false
}));
compiler = webpack(webpackConfig);
compiler.run(function(err, stats) {
if (err) {
throw err;
}
done();
});
}
module.exports = {
watchOptions: watchOptions,
development: development,
production: production,
};
Here are the contents of my webpack.conf.js file:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval-cheap-module-source-map',
bail: false,
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'assets/js'),
path.resolve(__dirname, 'node_modules/#bigcommerce/stencil-utils'),
],
query: {
compact: false,
cacheDirectory: true,
presets: [ ['es2015', {loose: true}] ]
}
}
]
},
plugins: [],
watch: false
};

Categories

Resources