Webpack Config for Static Pug/HTML Pages - angularjs

I'm transitioning a site to use Webpack, and I need a little help with configuration. I have a few pages written in Pug/Jade that are large and infrequently accessed (think Terms of Service or Privacy Policy). Most of my .jade files are Angular templates, so those are inlined in their components and it works well. These few files, however, I would like Webpack to compile into static HTML files served separately from the rest of the app. However, I would still like their file names to include a hash.
The basic idea I've come up with is like this:
In routes.ts:
$routeProvider.when('/_tos', templateUrl: require('./resources/terms-of-service.jade'))
In webpack.config.js's list of loaders:
{
test: /resources.*\.jade$/,
loaders: ['file?name=[name].[hash].html', 'pug-html']
}
I've tried that with various combinations of pug-loader, pug-html-loader (with and without the ?exports=false option), html-loader, extract-loader, extract-text-webpack-plugin, and file-loader, but everything I try has extra artifacts in the resulting .html file. E.g. it might start with module.exports =, or it might put \" everywhere in the file that should just have ".
Can anyone help?

Gah! I finally figured it out. I fundamentally misunderstood the way the list of loader works. I assumed only the first loader in the array that matched was used, but no, all loaders that match are used. (Though I'm still fuzzy on the details.) Here is a working configuration, where resources is the path to my "resources" directory:
loaders: [
{
test: /\.jade$/,
include: [resources],
loaders: ['file?name=[name].[hash].html', 'pug-html?exports=false']
},
{
test: /\.jade$/,
exclude: [resources],
loaders: ['pug-html?doctype=html']
}
]

Related

Using file-loader to load binary file in react

I am trying to load a file from a folder using a name from react props.
when I write this:
import FileImage from '!!file-loader!../public/uploads/file-1589134024728.file';
<img src={FileImage}/>
everything works (but is static). In elements I see:
<img src="368d70b7855164f45e8b1c68db4d549c.file">
[![working][1]][1]
But using this:
src={`!!file-loader!../public/uploads/${file}`}
will show as
<img src="!!file-loader!../public/uploads/file-1589134024728.file">
[![not working][2]][2]
GET http://localhost:8080/public/uploads/file-1589134024728.file 404 (Not Found)
I also tried
src={`../public/uploads/${file}`}
while webpack.config.js looks like that:
{
test: /\.(woff(2)?|ttf|eot|svg|file)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}```
I believe I somehow need to return [contenthash].[ext] but how?
[1]: https://i.stack.imgur.com/ZDx6l.png
[2]: https://i.stack.imgur.com/lCnMd.png
These files look like they are uploaded, which means you don't have access to their names at build time. This is ok, you have the file name.
You need to make sure that the /uploads/ directory is available through your HTTP server, and then you can use src={'/uploads/' + file} to load the resource from that location.
Even if these are not user uploads, but static files that you provide, then you can put them in your public/uploads directory and still just link them using their location on the webserver. It's hard to be sure without knowing where file comes from.

How to override a webpack loader based on specific require needs?

I'm building a documentation site in which I want to display demo code snippets.
With the styles, it was really straight forward, as my app is only including the main.scss, so I'm processing that file with all the necessary loaders to compile it, and any other scss file is loaded using the raw-loader to get the file as plain text.
The problem I'm having is at the moment of doing the same with my components. Unlike my styles, I need to include my components both when I want to render them using babel-loader, but I also want to import them as plain text for the demo showcase.
At first I thought of compromising using an inline loader at the require level
const componentCode = require('raw-loader!./path/to/component');
The problem with this approach is that by the time I try to do this import, the file has already been ran through babel-loader so I get the compiled version of the file instead of the original. I tried passing ?enforce=pre as a query parameter to the raw-loader inline, but this had no effect.
I was wondering if there is a way of defining a rule to override an import/require statement.
According to the webpack documentation
It's possible to overwrite any loaders in the configuration by prefixing the entire rule with !.
However, I can not find any examples of this. I tried the following, which compiled but crashed right after the first ! prefixed require without any errors
webpack.coonfig.js
{
test: /\.(js|jsx)$/,
exclude: [/node_modules/],
use: [
{
loader: 'babel-loader',
options: {
presets: ['env', 'react'],
},
},
],
},
{
test: /!*\.(js|jsx)$/,
enforce: "pre",
use: [
{
loader: 'raw-loader',
},
],
},
file.jsx
const componentCode = require('raw-loader!./path/to/component');
I also thought about reading the file using the fs but not sure if this will work. In the end the code will be compiled in its entirety by webpack and only the bundle will be published. Would this be the right approach?
Found my answer at Webpack - ignore loaders in require()?, Basically I need !! before the require to ignore the pre loaders and apply mine

(React + Webpack) Images Loading in Dev, but not Production (file-loader + image-webpack-loader)

Everything works great in development, but when I try to build for production, the images don't show up on the page. They do show up in proper folder (i.e. my production folder has an images subfolder with the images present). When I look at the folders (Sources) in the browser, the images folder is not present. It seems like the react build isn't aware of the folder for some reason even though webpack is building it properly. I'm guessing this is a react issue and not a webpack issue, but I'm still new to both. All of the resources that I have found seem to indicate that what I have should work, but I feel like I'm missing something.
webpack.config.js:
rules: [
...
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
'file-loader?name=[name].[ext]&publicPath=/&outputPath=images/',
'image-webpack-loader'
]
},
]
In use:
<img src={ require( './images/shopping-cart.png' ) } alt="shopping cart" />
Edit: I now have the image folder showing up with the image in it (ostensibly), however, the image is completely broken. Even just inspecting it in the browser from the folder does not work.
So it seems the answer was just to change '/' to './' and 'images/' to './images/'. I arrived at this through experimentation. Hopefully the answer helps someone else down the road.
rules: [
...
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
'file-loader?name=[name].[ext]&publicPath=./&outputPath=./images/',
'image-webpack-loader'
]
},
]

Webpack 1 + sass (in react) - leave my images alone

I have a project in React.js with SASS and using Webpack 1.
I have images folders with all the images and other assets' folders.
I do not want webpack to do anything with images, I want them to be loaded at the runtime by url.
I solved it in JSX by using image urls inline in the jsx code (rather then importing them) and it's working great.
But when I'm trying to do the same in SASS, it's different:
I used to refer to them in absolute pass /images/abc.png and it worked.
I didn't even had a webpack loader for them, it just worked.
But I had to change it to the relative path ../../www/images/abc.png and it's all broke down:
It refuses to work without webpack loader - just gives errors for each image.
I've tried using file-loader, but it copies all sass's used images into build folder.
I've tried using url-loader, but it just included the images into resulting css file making it enormously bloated.
So, what could I use to ignore the images from sass and just address them by url in the runtime?
Thanks
One possibility is to set the url option of the css-loader to false, so webpack won't touch the urls. Your rule for .scss could look something likes this (assuming you use extract-text-webpack-plugin):
Webpack 1:
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader?url=false!sass-loader')
},
Webpack 2:
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{ loader: 'css-loader', options: { url: false } },
{ loader: 'sass-loader' }
]
})
}
But that ignores all urls not just your images. If that is a problem you could use file-loader with the option emitFile: false so it won't copy your files. But you'll need some workaround to get the correct path. When using [path] in the name it will use the relative path from the context. Because you're building it to a directory (e.g. build/) you'll need to go up one directory (../) by setting the publicPath option. Which would give you the following rule:
Webpack 1:
{
test: /\.png/,
loader: 'file-loader?emitFile=false&name=[path][name].[ext]&publicPath=../'
},
Webpack 2:
{
test: /\.png/,
loader: 'file-loader',
options: {
emitFile: false,
name: '[path][name].[ext]',
publicPath: '../'
}
}
If you've set context in your webpack config or your output CSS file is more than one level deep in the build directory, you'll need to tweak the publicPath option.

Webpack vendor chunk auto creation

I want to create two webpack chunks: app.js and vendor.js
Currently I have smth like:
entry = {
psw: DIR.src,
vendor: ["angular", "angular-ui-router", "angular-bootstrap"]
};
...
plugins.push(new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.bundle.js'))
(i.e. like here https://github.com/christianalfoni/react-webpack-cookbook/wiki/Split-app-and-vendors)
This works fine (At least it works and looks ok). However I want to generate that 'vendor' array automatically. Any ideas how that can be done?
Got it using SplitByPath plugin. It puts to separate bundle js as well as css, so its very nice to use. Dont know why it is referenced so rare.
config.plugins.push(new SplitByPathPlugin([{ name : 'vendor', path: [path.join(__dirname, 'node_modules'), path.join(__dirname, 'bower_components')]}]));

Resources