Webpack how to negative match resource query - javascript

How can I add a resource query to my Webpack configuration so that if a require statement contains a query string, Webpack skips the loader I've specified in the configuration file. Consider the following configuration:
test: /\.(jpe?g|png|svg|gif|ico|webp)$/,
resourceQuery: /(?!ni-ignore)/i,
use: [
{
loader: "url-loader",
options: {
limit: 8192,
fallback: "file-loader",
publicPath: `/static/images/`,
outputPath: `/static/images/`,
name: "[name]-[hash].[ext]"
}
}
]
I want Webpack to skip the rule if a require statement contains ni-ignore query.
// should skip the rule
const image = require("./image.jpg?ni-ignore");
// should follow the rule
const image = require("./image.jpg");
Is there any way to add a negative resource query matcher?

Try this
resourceQuery: /^((?!ni-ignore).)*$/i
It seems that a part was missing in regex.

I know this is a bit old, but in case someone still needs this, resourceQuery now accepts negative rules in the form of:
resourceQuery: { not: [/raw/] },
See https://webpack.js.org/guides/asset-modules/#replacing-inline-loader-syntax for more details.

Related

webpack: question mark after [ext] in config file

webpack.config.js, under rules:
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
what does ?[hash] do?
The name parameter under the options object indicates what your file name will be evaluated to. In the [hash] case more specifically, where to place the generated content hash for the file.
So, the following config:
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]?[hash]'
}
}
Would generate something like:
path/to/file.png?e43b20c069c4a01867c31e98cbce33c9
The purpose for that is ability to easily invalidate these files when new versions are available. By having an unique hash to each file version,
the browser will discard the old one when there's a new version
You can specify hash types (md5, sha256, etc) and other configurations, read more:
https://webpack.js.org/loaders/file-loader/
Someone can correct me if I'm wrong, but I believe it has to do with adding a query string to bypass browser caching so that when you recompile, the newest version of your resources (source code or other resources) is loaded instead of an old cached version. And the hash is just so that the query string is based on the content of your raw resource.
hash is basically calculated for a build.
hash returns the build hash. If any portion of the build changes, this changes as well. check here and here for more details

Using CSS in Webpack

I've inherited a web app that uses webpack. In my app, I have a directory called "pub", which looks like this:
./pub
/styles
app.css
/images
brand.png
I have been trying unsuccessfully all morning to use these via webpack. In my webpack.config.js file, I have the following:
const path = require('path');
const projectRoot = path.resolve(__dirname, '../');
module.exports = {
entry: {
app: './src/index.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
loader: "style-loader!css-loader"
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
};
Then, in my index.js file, I have the following:
import logoImage from './public/images/brand.png';
require("css!./public/css/app.css");
When I run webpack, I receive an error that says:
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders.
You need to specify 'css-loader' instead of 'css',
see https://webpack.js.org/guides/migrating/#automatic-loader-module-name-extension-removed
I don't really understand this error. When I look at it, and then I look at my webpack.config.js file, it looks to me like I'm using css-loader. Beyond that though, how do I use a style in my webpage once the require statement is working. I'm just trying to use webpack with a web app and want to import my brand and CSS and I can't figure it out.
You don't need the css! in your require statement
require("css!./public/css/app.css");
You can just use
require("./public/css/app.css");
Because you are testing files with:
{
test: /\.css$/, // <-- here
loader: "style-loader!css-loader"
},
Or without the rule in your webpack config
// No test in rules matched but you tell webpack
// explicitly to use the css loader
require("style-loader!css-loader!./public/css/app.css");
Your hierarchy is pub/styles/app.css but the location you use in your require is public/css/app.css. It looks like you're trying to call your css from the wrong location.
If this doesn't solve your issue, check out this link https://webpack.github.io/docs/stylesheets.html
The first step on that page is to install css-loader and configure it, this might be a good place to start.

Import Javascript files as a string?

I want to be able to simply do an import file from 'file.js and then have file be a string of the contents within file.js. I've toyed around with raw-loader but it doesn't give me the same contents (instead it loads it in a different format). Any suggestions?
it doesn't give me the same contents (instead it loads it in a different format)
That seems to mean that there are other loaders from your config applied to the file. You can enforce that only the loader in the import statement is used by prefixing it with a !:
import file from '!raw-loader!file.js'
From the docs:
It's possible to overwrite any loaders in the configuration by prefixing the entire rule with !.
In Webpack 5 it's possible to handle it without raw-loader.
It's enough to add a rule with type: asset/source (see the docs). Note that in this case, if you use babel loader or other JS loaders, the code will still be processed by them if not overridden manually.
A simplified code example:
module: {
rules: [
{
test: /(?<!boilerplate)\.js$/, // a negative look-behind regex to exclude your file
exclude: /node_modules/, // also can be handled here, adding a folder with file(s) to be excluded
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /boilerplate\.js$/,
type: 'asset/source'
},
]
}

Use Babel Transform inside of React code

I'm trying to convert a string to valid JSX code, and then inject it into my React component.
const babel = require('babel-core')
let result = eval(babel.transform('<p className="greeting">Hello</p>').code)
But am getting hit with a wall of errors, because I'm trying to use Babel in the browser:
ERROR in ./~/babel-core/lib/api/node.js
Module not found: Error: Can't resolve 'fs' in '/Users/ben/Desktop/Work/code/ru-coding-challege/node_modules/babel-core/lib/api'
# ./~/babel-core/lib/api/node.js 72:10-23
# ./~/babel-core/index.js
# ./src/js/containers/app-container.js
# ./src/js/index.js
# multi (webpack)-dev-server/client?http://localhost:3000 ./src/js/index.js
...more similar errors
Yes, I know creating code from a string and injecting it is frowned upon, but D3 creates elements dynamically (i.e. you can't write them declaratively) For example: axes whose values and number of ticks change based on the data. I've successfully changed the D3 axes into JSX with htmltojsx but that returns a String. I need to turn that String into valid JSX components that I can inject into my code.
EDIT: As Michael Lyons states below, I could just use dangerouslySetInnerHTML, but I am trying to avoid this option unless everything else doesn't work. Trying to stay within the React paradigm as much as possible.
Here's how my component's render method would look:
<svg width='100%' height='600'>
<g transform='translate(50, 50)'>
<path d='...' className='path-0'></path>
</g>
{/* Insert JSX elements here. e.g. axes below */}
{axes}
</svg>
And here is my webpack.config.js
const CopyWebpackPlugin = require('copy-webpack-plugin')
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: './src/js/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].bundle.js',
},
devServer: {
inline: true,
contentBase: path.join(__dirname, 'dist'),
port: 3000
},
plugins: [
new CopyWebpackPlugin([
{ from: 'src/html/index.html' }
]),
new webpack.DefinePlugin({
IN_BROWSER: true,
}),
],
module: {
loaders: [
{
test: /\.scss$/,
exclude: /(node_modules)/,
loader: 'style-loader!css-loader!sass-loader'
},
{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
}
]
}
}
Instead of translating HTML to JSX, then rendering with babel in your code while on the client, you could render that html directly through your React component.
Facebook's DOM element implementation has built in functionality for this use-case, and you are right it is generally frowned upon for security reasons because it opens up vulnerabilities to cross-site scripting.
Facebook has even labeled it "dangerouslySetInnerHTML" to remind devs that this is dangerous.
So if you have HTML in a string format, you can render that in JSX in a manner such as this:
getMarkup() {
return { __html: '<p class="greeting">Hello</p>' }
}
render() {
return <div dangerouslySetInnerHTML={this.getMarkup()} />;
}
This comes straight from the React DOM elements documentation here: Docs
This method should also allow you to bypass having to convert your d3 output to JSX
Edit: Introductory sentence

webpack loaders and include

I'm new to webpack and I'm trying to understand loaders as well as its properties such as test, loader, include etc.
Here is a sample snippet of webpack.config.js that I found in google.
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [
path.resolve(__dirname, 'index.js'),
path.resolve(__dirname, 'config.js'),
path.resolve(__dirname, 'lib'),
path.resolve(__dirname, 'app'),
path.resolve(__dirname, 'src')
],
exclude: [
path.resolve(__dirname, 'test', 'test.build.js')
],
cacheDirectory: true,
query: {
presets: ['es2015']
}
},
]
}
Am I right that test: /.js$/ will be used only for files with extension .js?
The loader: 'babel-loader', is the loader we install using npm
The include: I have many questions on this. Am I right that anything we put inside the array will be transpiled? That means, index.js, config.js, and all *.js files in lib, app and src will be transpiled.
More questions on the include: When files get transpiled, do the *.js files get concatenated into one big file?
I think exclude is self explanatory. It will not get transpiled.
What does query: { presets: ['es2015'] } do?
In webpack config there are multiple things for configuration, important ones are
entry - can be an array or an object defining the entry point for the asset you want to bundle, can be a js as test here says do it only for /.js$. Your application if has multiple entry points use an array.
include - defines the set of path or files where the imported files will be transformed by the loader.
exclude is self explanatory (do not transform file from these places).
output - the final bundle you want to create. if you specify for example
output: {
filename: "[name].bundle.js",
vendor: "react"
}
Then your application js files will be bundled as main.bundle.js and react in a vendor.js files. It is an error if you do not use both in html page.
Hope it helped
This documentation helped me understand better. Looks like it is for webpack 1 but still applies.
https://webpack.github.io/docs/configuration.html#module-loaders
Loaders
An array of automatically applied loaders.
Each item can have these properties:
test: A condition that must be met
exclude: A condition that must not be met
include: An array of paths or files where the imported files will be transformed by the loader
loader: A string of “!” separated loaders
loaders: An array of loaders as string
This example helped me understand what is going on. Looks like you use either include or exclude but not both. The test is a condition applied to all files. So if you include a folder, each file must pass the test condition. I have not verified this, but based on the example provided by the documentation, it look like that is how it works.
module: {
rules: [
{
// "test" is commonly used to match the file extension
test: /\.jsx$/,
// "include" is commonly used to match the directories
include: [
path.resolve(__dirname, "app/src"),
path.resolve(__dirname, "app/test")
],
// "exclude" should be used to exclude exceptions
// try to prefer "include" when possible
// the "loader"
loader: "babel-loader" // or "babel" because webpack adds the '-loader' automatically
}
]
}
1) Correct.
2) Correct.
3) Correct.
4) I am unsure. My webpack.config.js file includes an output key, and does bundle it all into one file:
output: {
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js'
}
5) Correct.
6) This tells babel-loader what sort of transpile you want it to perform, as well as other compile options. So, for example, if you want it to transpile jsx as well + cache results for improve performance, you would change it to:
query: {
presets: ['react', 'es2015'],
cacheDirectory: true
}

Categories

Resources