Copy multiple html files with webpack2 (from src to dist folder) - html

Which loader/plugin should I use to move multiple html files from one folder (src) to another (dist) which only imports files that obey certain rules in this example I need to import multiple html files, so the regex would be:
/.html$/
I know that I can move html using html-webpack-plugin but I don't want to create object instance for every page I want to move. I also don't want to make multiple imports in my app.js (entry point for webpack).
So i tried with copy-webpack-plugin but this one moves everything from src to dist. Is it possible to filter with my regex pattern or do you know other way that works to do this?
new CopyWebpackPlugin([{
from: './src',
to: path.resolve(__dirname, "dist")
}],
I gues that I could use system
mkdir dist && cp ./src/*.html ./dist
And simply run this in my package.json in the script before running webpack -d
but this is not the "polite" way of doing this. I'm sure that webpack can do that easily..
Ps. Also, it would be nice to minimize those files, if possible.

Moving all files in batch
So for now it works like this. To not have to include every single file from the src folder in to my app.js (which is my entry point for webpack) I required all files using require.context()
Because my app.js is also in my src folder I use relative path to require all other file:
// requires all files in current directory and sub directories
require.context("./", true, /^\.\/.*\..*/);
Or if you want to import files with certain extension sue this instead:
// requires all html files in current directory and sub directories
require.context("./", true, /^\.\/.*\.html/);
So now everything is imported and I don't have to require files manually. The only thing I have to do is set entry to app.js using path.resolve.
I now can use test property to get what I want from within in webpack.config.js module rules.
...
module: {
rules: [
{
test: /\.(html)$/,
use:
[
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: './src',
outputPath: '/',
publicPath: '/'
}
},
...
This works fine my files are moved (but not minified). Perhaps someone can take this a little bit further and the answer will be completed.
Below i place full file for reference only
webpack.config.js
// imports node plugin which allows us to save data to a file for example css external files
var ExtractTextPlugin = require("extract-text-webpack-plugin");
// cleans defined folders before webpack will build new files now we can remove package.json commands "rm -rf ./dist && ..."
var CleanWebpackPlugin = require("clean-webpack-plugin");
// copies to memory html from template file and injects css and javascript as well as img src to newly generated html file.
var HtmlWebpackPlugin = require("html-webpack-plugin");
// to include jquery we need to import 'jquery' in app.js but also we need to make connection between bundle.js jquery script
var Webpack = require('webpack');
// includes node path resover that is need for webpack-dev-server to run properly
var path = require('path');
// webpack configuration
module.exports = {
entry: [
path.resolve(__dirname, "src/app.js"),
],
output: {
path: path.resolve(__dirname, 'dist'), // defins the main utput directory
filename: 'js/bundle.js',
},
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 8080,
},
module: {
rules: [
{
test: /\.(html)$/,
use:
[
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]',
context: './src',
outputPath: '/',
publicPath: '/'
}
},
]
},
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'img/',
publicPath: '/' // this path relates to reference path from the index.html file that imports out bundle.js file
}
}
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015']
}
}
]
},
{
test: /\.sass$/,
include: [
path.resolve(__dirname, "src/sass")
],
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
//resolve-url-loader may be chained before sass-loader if necessary
use: [
{
loader: 'css-loader',
options: {
minimize: false,
sourceMap: true,
}
},
'sass-loader'
]
})
},
]
},
plugins: [
// mapping jQuery variable to our node module dependency (remember to import 'jquery' in app.js)
// below we make jquery available as both the $ and jQuery variable
new Webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
}),
// use extract plugin to build an external file loded by sass-loader > complied to css > movig to bundle.css
new ExtractTextPlugin({
filename: 'css/bundle.css'
}),
// remove all files from this folder before generating new files
// new CleanWebpackPlugin(['dist']),
],
}

You should be able to use copy-webpack-plugin's support for globs to achieve what you want.
new CopyWebpackPlugin([
{
from: './src/*.html',
to: path.resolve(__dirname, 'dist')
}
])
The globs accept minimatch options too.
EDIT:
In addition, if you're copying just HTML (and want to minify them), you might want to take a look at html-webpack-plugin. The minify option allows you to minify those HTML files.

Related

File-loader creating 2 images and linking the wrong one

file-loader is creating two separate images in my build folder. One is the named correctly and saved in the correct path, the other is named [hash].png (which is the default) and is stored in build, not build/images. The second incorrect file is 0 bytes; this is the one being linked in the final index.html file in the build folder. I've defined both outputPath and publicPath. publicPath doesn't seem to actually do anything though, regardless of what I put there. Am I misunderstanding what it does?
module.exports = {
entry: {
index: './app/main.js',
vendor: './app/vendor.js'
},
output: {
path: path.resolve(__dirname, './build'),
filename: '[name].[contenthash].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/, /api/, /tests/, /coverage/],
use: 'babel-loader'
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.html$/,
use: 'html-loader'
},
{
test: /\.(svg|png|jpg|gif)$/,
use:{
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'images/',
publicPath: 'images/'
}
}
},
]
},
plugins: [
new HtmlWebpackPlugin({ template: './app/index.html' }),
new CleanWebpackPlugin()
]
};
Image link in final html:
<img src="465107fe07e3ec18a463.png">
Another post with the same issue that didn't get any answers:
Webpack, I am trying to use file loader to load images but whenever i run build i get 2 images not 1 and the one linking to the html file is wrong
I eventually figured it out. As of Webpack 5.0, this can be handled without installing a loader at all. So file-loader, url-loader, raw-loader, etc. are now obsolete.
https://webpack.js.org/guides/asset-modules/
This is a problem of file-loader v6.
I solved this with the way adding esModule option.
Both html-loader, css-loader and loader that using image url need the esModule option false.
Or you should use the file-loader except v6.
{
loader: 'css-loader',
options: {
esModule: false
}
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},

Webpack - Yaml -> JSON -> Extract file

I have a YAML file with a few translations. I need to transform these files into a JSON file. I've tried using yaml-import-loader and json-loader but I get an error.
Here's my setup:
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractEnglish = new ExtractTextPlugin('lang/en.js');
module.exports = {
entry: [
'./src/locales/application.en.yml',
],
output: {
filename: 'english.js',
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.en\.yml$/,
use: extractEnglish.extract({
use: [
// { loader: 'json-loader' },
{
loader: 'yaml-import-loader',
options: {
output: 'json',
},
}],
}),
},
],
},
plugins: [
extractEnglish,
],
};
And the error I get:
Users/xxx/Documents/Project/node_modules/extract-text-webpack-plugin/dist/index.js:188
chunk.sortModules();
^
TypeError: chunk.sortModules is not a function
at /Users/xxx/Documents/Project/node_modules/extract-text-webpack-plugin/dist/index.js:188:19
Same error whether or not the json-loader is commented or not.
I really don't understand what is going wrong.
Versions:
"webpack": "2.6.1",
"extract-text-webpack-plugin": "^3.0.0",
"json-loader": "^0.5.7",
Not sure if this will help your situation but I recently found a solution to my i18n loading problem. I do this to extract YAML into JSON files upfront as I use angular-translate and needed to load files dynamically and on-demand. I avoid extract-text-webpack-plugin and use only loaders: file-loader and yaml-loader.
First I setup the import of my .yaml files near the beginning of source (in my case a specific chain of import files for webpack to process)
import "./i18n/en.user.yaml";
I updated webpack config to translate YAML to JSON and have it available to load dynamically (everything originates from my 'src' directory, hence the context):
rules: [{
test: /.\.yaml$/,
use: [{
loader: 'file-loader',
options: {
name: '[path][name].json',
context: 'src'
}
},{
loader: 'yaml-loader'
}]
}]
This will translate my yaml file(s) and export them to my public directory, in this case at '/i18n/en.user.json'.
Now when angular-translate uploads my configured i18n settings via $http on-demand, it already has the parsed YAML and avoids having to parse it with js-yaml (or similar) on the front end.
A relatively old question, but I found it while searching for a solution to the same problem, so I thought it worth to chip in.
If you're not really using translation files in your code (i.e. you never import and use them directly) then using a Webpack loader is not the most elegant solution (you'd be forced to import them just so that the loader could be triggered and perform the conversion).
An alternative would be to use the CopyWebpackPlugin instead: it supports a transform option, which takes a function receiving the content of the file as a Buffer.
With a YAML parser (like js-yaml) as an additional dependency, adding this to your Webpack configuration would work:
const yaml = require('js-yaml');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
// OTHER WEBPACK CONFIG HERE
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from: 'i18n/**/*',
to: 'i18n/[name].json',
transform(content) {
return Buffer.from(
JSON.stringify(
yaml.load(content.toString('utf8'), {
schema: yaml.JSON_SCHEMA
})
),
'utf8'
)
}
}
]
})
]
}
The i18n folder in the above example would contain your .yml translations.
The Copy plugin would load them, convert them to JSON, and save them in the output folder under i18n/ (as specified by the to option).

Webpack unable to get json file

I am new to Webpack and I am having a hard time to understand how I can access the content of my json file being added in entry and loaded using json-loader:
entry :
en: {
`${config.basePaths.tmp}script.js`,
`${config.basePaths.tmp}en.json`
}
},
output: {
publicPath: '/js/',
path: `${config.paths.scripts.dist}`,
filename: `[name].script.js`
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
},
{
test: /\.coffee$/,
loader: 'coffee-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
}
The object is added to my output file (en.script.js) but I have no clue how to access it... It looks like this:
function(module, exports) {
module.exports = {
"en": {
"title": "I love webpack",
"something": "else"
}
};
}
Please help me.
You should not put a JSON file as the entry point. Entry points are meant to be the starting point of your app and if you specify multiple files per entry point it's just to include them in the same bundle, but they don't really interact with each other (see Concepts - Entry Points).
Instead with webpack you can import files that are not JavaScript, such as .json, and if you have an appropriate loader it will turn that into valid JavaScript which you can use just as any other JavaScript you import. So in your script.js (your entry point) you can import the JSON with:
import enJson from './en.json';
Now you can use enJson as you want, which contains the JavaScript representation of en.json. And by the way remove that from your entry, because webpack will figure out which files are used by looking what is imported from your entry point (and all its dependencies).
entry : {
en: `${config.basePaths.tmp}script.js`,
},

Concat and minify CSS files with Webpack without require them

I've got and old part of an application that contains some CSS files that are concatenated and minified with gulp script.
And I've got a new application that bundled with Webpack.
Is it possible to assemble the old CSS with Webpack without any additional require calls? Just get all CSS from old_css/**/*.css, concat, minify and write to assets/old.css?
You can achieve this by "requiring" the CSS files through a separate entry. You'll end up with something like this:
{
entry: {
styles: glob('old_css/**/*.css'), // array of css files
...
},
output: {
filename: '[name].[chunkhash].js',
...
},
module: {
loaders: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
...
]
},
plugins: [
new ExtractTextPlugin('[name].[chunkhash].css'),
...
],
...
}
You'll end up with a JavaScript file named after your style entry in addition to the CSS file. You can ignore that, though.

Webpack with chunkFileName and source-maps

A project I'm working on is using the code splitting facility of Webpack. I'm having trouble actually getting source maps to work with it. I've used source maps successfully on other projects that don't use code splitting and wonder if this is the issue. The output from gulp task indicates that source maps are indeed being created - they just don't appear to be available in Chrome.
This is the relevant section of my gulp file.
files = globule.find(['./src/Components/*.*', '!./src/**/*-test.js']);
gulp.src(files)
.pipe(webpack({
entry: "./src/components/settings.js",
output: {
filename: 'Settings.js',
publicPath: "/admin/Content/Scripts/apps/",
chunkFilename: "[name].js"
},
module: {
loaders: [{
test: /\.js$/,
exclude: /(node_modules)/,
loader: 'babel-loader'
},{
test: /\.json$/,
loader: 'json-loader'
},{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader',
'css-loader')
}]
},
devtool: 'source-map',
resolve: {
extensions: ['', '.js', '.jsx', '.json'],
alias: {
'reactuifw': process.env.NODE_ENV === 'development'
? process.env.REACT_UIFW + 'react-uifw.js' : 'react-uifw', 'react' : __dirname + '/node_modules/react'
}
},
externals: {
jquery: '$'
},
cache: true,
plugins: [new ExtractTextPlugin('bundle.css')]
}))
Any idea whats wrong?
I've never gotten proper source maps working with devtool: 'source-map'; I think maybe it's shorthand for a particular config of the SourceMapDevToolPlugin? I use the plugin explicitly instead of using the 'devtool' option, with config as described in this github issue (ignore the WebStorm stuff). The issue has to do with the sourceRoot used in the maps. Maybe give that a shot and see if you get usable maps?