How to add webfonts and images loaders to webpack - node.js

I would like to include webfonts and image loader to my project. I have the following rules in my webpack config:
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: "file-loader",
options: {
outputPath: "./images",
publicPath: "./images",
name: "./[name].[ext]",
},
},
],
},
{
test: /\.(woff|woff2|eot|ttf|svg)$/,
loader: "url-loader",
options: {
outputPath: "./webfonts",
publicPath: "./webfonts",
name: "./[name].[ext]",
},
},
But when I run npm run build it builds the webfonts into the /images folder in the dist folder. How can I prevent webpack from doing this?

Related

Programmatic Webpack & Jest (ESM): can't resolve module without '.js' file extension

I'm using webpack programmatically, with typescript, ESM, and jest. In a jest test I'm getting errors for not including a .js file extension when importing ES modules. For example:
Module not found: Error: Can't resolve 'modulename' in '/path/components'
Did you mean 'modulename.js'?
BREAKING CHANGE: The request 'modulename' failed to resolve only because it was resolved as fully specified
(probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
The module in question does indeed have "type": "module" set in its package.json. I have tried adding .js to the import, and it doesn't help.
I'm invoking jest with:
node --experimental-vm-modules --experimental-specifier-resolution=node node_modules/jest/bin/jest.js
as is recommended in the docs (everything else works except webpack). Note that I have tried with and without --experimental-specifier-resolution=node (this has helped in other similar circumstances).
Any thoughts on how to get webpack to work? Thanks in advance!
Note: everything was working until it was all converted to ESM! Now only programmatic webpack isn't working.
Webpack config:
{
entry,
target: 'web',
output: {
path: outputDir,
filename: '[name].js',
},
mode: process.env.NODE_ENV as 'development' | 'production' | 'none' | undefined,
resolve: {
extensions: [
'.ts',
'.tsx',
'.js',
'.jsx',
'.ttf',
'.eot',
'.otf',
'.svg',
'.png',
'.woff',
'.woff2',
'.css',
'.scss',
'.sass',
],
},
module: {
rules: [
{
test: /\.(ttf|eot|otf|svg|png)$/,
loader: 'file-loader',
},
{
test: /\.(woff|woff2)$/,
loader: 'url-loader',
},
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
sourceType: 'unambiguous',
presets: [
[
'#babel/preset-env',
{
corejs: '3.0.0,',
useBuiltIns: 'usage',
},
],
'#babel/preset-react',
'#babel/preset-typescript',
],
plugins: [
'css-modules-transform',
[
'babel-plugin-react-scoped-css',
{
include: '.scoped.(sa|sc|c)ss$',
},
],
'#babel/plugin-proposal-class-properties',
],
},
},
{
test: /\.(sc|c|sa)ss$/,
use: [
'style-loader',
'css-loader',
'scoped-css-loader',
'sass-loader',
],
},
],
},
}
Ok so I found the solution here.
Basically, had to add 2 things to the webpack config under module.rules:
{
test: /\.m?js/,
type: "javascript/auto",
},
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
#nerdlinger answer worked for me. I had this webpack.config.js
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
],
}
...
}
and i changed it to this
module.exports = {
entry: './src/index.js',
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
},
resolve: {
fullySpecified: false,
}
}
],
}
...
}

Webpack Babel build fails when importing files outside entry path

I have this project that i'm already using webpack + babel to build. I've hit a wall since what i want to do is share some constants between my node (server) and my react app (front-end).
My project structure is this
- app
- internals
- webpack
- different webpack configs (node, react-dev, react-production etc)
- server
- shared
- .babelrc
I've put some "constants" files into the shared folder that I use both from my app and from my server.
When I try to build my server I get this
ERROR in ./shared/reports.constants.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
TypeError: Cannot read property 'code' of null
at transpile (C:\Users\XXX\Desktop\XXX\XXX\node_modules\babel-loader\lib\index.js:70:21)
at Object.module.exports (C:\Users\XXX\Desktop\XXX\XXX\node_modules\babel-loader\lib\index.js
:173:20)
Below is my webpack config file. Any ideas what might be wrong ?
{
mode: 'production',
target: 'node',
externals: nodeExternals(),
entry: {
server: [path.join(process.cwd(), 'server/index.js')],
},
output: {
filename: '[name].js',
path: path.resolve(process.cwd(), 'build'),
// sourceMapFilename: '[name].js.map',
},
devtool: 'hidden-source-map',
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract(
{ fallback: 'style-loader', use: { loader: 'css-loader', options: { minimize: true } } }),
},
{ test: /\.jpg$/, use: [{ loader: 'file-loader', options: { name: '/images/[name].[ext]' } }] },
{ test: /\.md$/, use: [{ loader: 'markdown-with-front-matter-loader' }] },
{
test: /\.js$/,
exclude: [/node_modules/],
include: [/server/, /shared/],
use: [
'babel-loader',
{
loader: 'webpack-preprocessor-loader',
options: {
debug: process.env.NODE_ENV !== 'production',
directives: {
secret: false,
},
params: {
ENV: process.env.NODE_ENV,
DEBUG: process.env.NODE_ENV !== 'production',
PRODUCTION: process.env.NODE_ENV === 'production',
ENVIRONMENT: process.env.ENVIRONMENT,
},
verbose: false,
},
},
],
},
],
},
plugins
etc
}
.babelrc file
{
"presets": [
"#babel/preset-env"
],
"plugins": [
"react-hot-loader/babel",
"#babel/transform-runtime",
"transform-html-import-to-string"
]
}
I've added the /shared/ to the includes rules.
Thank you in advance
For some reason I already had a babel.config.js + the babelrc. All I had to do was go into the babel.config.js and add the shared folder to be included in the env => production.
Thank you for your time

How can I make __dirname in a node module refer to the directory that the webpack bundle is generated in?

I am learning Node.
I have a module which I use to read and write files to a directory which I am referencing in my module dataInterface.js as:
const dataInterface = {} as DataInterface;
dataInterface.baseDir = path.join(__dirname, '../.data/');
My directory and file structure is:
/app
/.data
/dist
/src
dataInterface.js
index.js
I use webpack with entry point index.js (which imports dataInterface.js), and the bundle output location is app/dist/index.js.
My webpack.config.js is
module.exports = {
{
entry: './index.ts',
watch: true,
target: 'node',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js',
},
module: {
rules: [
{ test: /\.tsx?$/, loader: 'ts-loader' },
{
test: /\.js?$/,
exclude: /(node_modules|build)/,
use: [{ loader: 'babel-loader' }],
},
],
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
node: {
__dirname: true,
},
};
}
The part
node: {
__dirname: true,
},
is important. When set to true, the reference to __dirname in dataInterface.js is src, so path.join(__dirname, '../.data/'); does resolve to the .data directory in the root folder.
But what I want is for __dirname to refer to dist, which is where the bundle is located. In that case ultimately I want to put .data in dist.
Is this possible and what am I missing in conceptual terms here?

Split assets into bundles in Production with Webpack

I see on almost every production website made in React (or in almost every other framework), that there are splitted css and js bundles inserted into HTML website.
I am using Webpack 4 with this configuration:
module.exports = {
entry: "./src/client/index.js",
output: {
path: outputPath,
filename: "[name].js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}, {
test: /\.css$/,
use: ['style-loader', 'css-loader']
}, {
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
devServer: {
port: 3000,
open: true,
proxy: {
'/api': 'http://localhost:8080'
}
},
plugins: [
new CleanWebpackPlugin([outputPath]),
new HtmlWebPackPlugin({
template: "./public/index.html"
})
]
};
But when I build my frontend and serve it by Express, my CSS styles are inlined by <style></style> and also included in main.js file.
How to split CSS,JS and other assets from each other (bundle.css, bundle.js, img/image1.png, etc) instead of inlining CSS and converting images into base64 format?
To create a new file for css, remove style-loader and add https://github.com/webpack-contrib/mini-css-extract-plugin
To do the same with files, remove url-loader and replace it with file-loader

Make webpack ignore a directory

I'm making a chrome extension that injects content scripts. I don't want Content scripts to be processed by webpack.
My directory structure:
/extension
|-manifest.json
|--scripts
|- background.js
|- content
|-- script1.js
|-- script2.js
|-- ...
Here's my gulp task that calls webpack:
gulp.task('js', (cb) => {
return gulp.src(['source/scripts/**/*.js'])
.pipe(plumber({
errorHandler: function(errors) {
}
}))
.pipe(named())
.pipe(gulpWebpack({
watch: args.watch,
module: {
rules: [
{
enforce: "pre",
test: /\.json$/,
loader: "json-loader"
},
{
enforce: "pre",
test: /\.(gif|jpe?g|png)$/,
loader: "file-loader?name=img/[name].[ext]",
},
{
enforce: "pre",
test: /content\//,
loader: "file-loader?name=content/[name].[ext]",
},
{
test: /\.js$/,
loader: "babel-loader",
exclude: [
/content/
]
}
],
},
}, null, (err, stats) => {
log(`Finished '${colors.cyan('js')}'`, stats.toString({
chunks: false,
colors: true,
cached: false,
children: false
}));
}))
.pipe(gulp.dest(`/scripts`))
});
I want to keep the directory structure in the build directory and not get the files inside content/ to be parsed, ie. to use the file-loader
But they're just getting parsed and my pre rule for content scripts is getting ignored.
Webpack will only process the files which are required by the script which you are compiling. It is not possible to do so as excluding directories with dependencies would break your project.
I've made a separate gulp task to copy those sort of scripts without any processing and excluded that same directory from the gulp task that calls webpack

Resources