I want to generate multiple pages which will have content on different languages from one common template. How can I do it with webpack?
I tried to use different webpack plugins like webpack-static-i18n-html, i18n-webpack-plugin but nothing works for me. The best thing I found is a webpack-static-i18n-html, but it has bad support and this plugin can't watch changes in JSON files with translated text. Below is what I have for now.
This is my code from webpack.common.js.
const Path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const StaticI18nHtmlPlugin = require("webpack-static-i18n-html");
//...
module.exports = {
//...
plugins: [
//...
new StaticI18nHtmlPlugin({
locale: 'en',
locales: ['en', 'ua', 'ru'],
baseDir: Path.posix.join(__dirname, ".."),
outputDir: 'src/localized-pages',
outputDefault: '__lng__/__file__',
localesPath: 'src/locales',
files: 'src/templates/index.html'
}),
new HtmlWebpackPlugin({
filename: 'index.html',
template: Path.resolve(__dirname, '../src/templates/index.html')
}),
new HtmlWebpackPlugin({
filename: 'ua/index.html',
template: Path.resolve(__dirname, '../src/localized-pages/ua/src/templates/index.html')
}),
new HtmlWebpackPlugin({
filename: 'ru/index.html',
template: Path.resolve(__dirname, '../src/localized-pages/ru/src/templates/index.html')
}),
//...
],
//...
};
I also have webpack.dev.js and webpack.prod.js which I merge with webpack.common.js via webpack-merge plugin. As you can see, after generating pages, I have to use HtmlWebpackPlugin to serve them. It's awkward to use.
locales folder:
locales
|-en.json
|-ua.json
|-ru.json
en.json file:
{
"key": {
"innerKey" : "value"
}
}
Then plugin generates from:
<p data-t>key.innerKay</p>
this
<p>value</p>
But as I said, If I change en.json nothing will regenerate. I will not use this way to generate multiple pages for different languages.
So, I would like to generate several pages from one template. Is there any way to do this with webpack?
I was working on a multi language admin dashboard with Webpack and was wondering how could I tackle this problem until I found a way to make everything automatic with a multiple language web template.
First of all, webpack-static-i18n-html isn't a good solution because most of its packages are deprecated. But actually the mentioned package is based on a good npm package called node-static-i18n. So, the first thing you need to do is installing this npm package using this command
npm install -g static-i18n
Next, you need to make your translation file as *.json files and in json format and put them in a folder which I named "locales" and I put it in my "src" folder of my project. I need two languages for my website. One of them is English and another is Farsi or Persian. Therefore I made two file namely fa.json and en.json. So, I have folder and file structure like the picture below:
My file and folder structure in my Webpack project
This is part of my en.json file as an example:
{
"menu": {
"items": {
"dashboard": "Dashboard",
"posts": "Posts",
"media": "Media"
},
"sub": {
"items": {
"all-posts": "All Posts",
"add-new-post": "Add New",
"categories": "Categories"
}
}
}
}
This is part of my fa.json file as an example:
{
"menu": {
"items": {
"dashboard": "پیشخوان",
"posts": "نوشته ها",
"media": "رسانه"
},
"sub": {
"items": {
"all-posts": "نوشته ها",
"add-new-post": "افزودن نوشته",
"categories": "دسته ها"
}
}
}
}
and you can use them in your html tags like this:
<span class="className" data-t>menu.items.dashboard</span>
Please notice that for using translation you should use the attribute data-t in your tags like span then you can use key and values saved in your related json file to use translations between your tags. for more information about data-t and its usage please go to the plugin's Github page that I mentioned it earlier in this text on the plugin name.
Next, you should write needed command in the script section of your package.json file to run node-static-i18n to translate your template based on your html template file and save them in i18n folder in root of your project as below:
"scripts": {
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
}
in the above command:
-l: The default locale.
-i: the list of locales to be generated.
--localesPath: The directory of the translations, where each file should be named LOCALE_NAME.json
Now if you run npm run i18n this command should make a folder in root path of your project called i18n containing html files in two languages in this case. it will be like the picture below:
i18n folder and translated html files in it
Next you should config your Html Webpack Plugin in your Webpack config file to show these pages in your browser like this:
plugins: [
.
.
.
new HtmlWebpackPlugin({
//inject: false,
chunks: ['main'],
template: 'i18n/index.html',
filename: 'index.html'
}),
new HtmlWebpackPlugin({
//inject: false,
chunks: ['main-rtl'],
template: 'i18n/fa/index.html',
filename: 'fa/index.html'
})
]
because you need to see changes on your browser automatically you need another package called npm-watch to install through this command:
npm install -D npm-watch
Then, you should change script section of your package.json like this:
"scripts": {
"i18n-watch": "watch 'npm run i18n' src",
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
}
By using the command npm run i18n-watch whenever you make any changes in your locale files or your original html template in src folder it's gonna re-translate your html file based on new information and if you're running your webpack dev server you can see the result right after you save changes.
After that, to run i18n-watch command and your Webpack dev server at the same time it would be great installing another npm package for this purpose called npm-run-all by using the command below:
npm i -D npm-run-all
Finally, you can change the script section of your package.json like this to run i18n-watch and your Webpack dev server at the same time and after that if you make any changes you can see the result in the browser right after saving changes.
"scripts": {
"i18n-watch": "watch 'npm run i18n' src",
"i18n": "static-i18n -l en -i fa -i en src --localesPath src/locales/",
"webpack-dev": "webpack-dev-server --open --config=config/webpack.dev.js",
"start": "npm-run-all --parallel webpack-dev i18n-watch"
}
Now, if you use npm start in your terminal you will see your Webpack dev server and i18n-watch are running at the same time watching for any changes.
Hopefully this makes sense.
Related
I'm trying to move from Gulp to Webpack. In Gulp I have task which copies all files and folders from /static/ folder to /build/ folder. How to do the same with Webpack? Do I need some plugin?
Requiring assets using the file-loader module is the way webpack is intended to be used (source). However, if you need greater flexibility or want a cleaner interface, you can also copy static files directly using my copy-webpack-plugin (npm, Github). For your static to build example:
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
context: path.join(__dirname, 'your-app'),
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'static' }
]
})
]
};
Compatibility note: If you're using an old version of webpack like webpack#4.x.x, use copy-webpack-plugin#6.x.x. Otherwise use latest.
You don't need to copy things around, webpack works different than gulp. Webpack is a module bundler and everything you reference in your files will be included. You just need to specify a loader for that.
So if you write:
var myImage = require("./static/myImage.jpg");
Webpack will first try to parse the referenced file as JavaScript (because that's the default). Of course, that will fail. That's why you need to specify a loader for that file type. The file- or url-loader for instance take the referenced file, put it into webpack's output folder (which should be build in your case) and return the hashed url for that file.
var myImage = require("./static/myImage.jpg");
console.log(myImage); // '/build/12as7f9asfasgasg.jpg'
Usually loaders are applied via the webpack config:
// webpack.config.js
module.exports = {
...
module: {
loaders: [
{ test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/, loader: "file" }
]
}
};
Of course you need to install the file-loader first to make this work.
If you want to copy your static files you can use the file-loader in this way :
for html files :
in webpack.config.js :
module.exports = {
...
module: {
loaders: [
{ test: /\.(html)$/,
loader: "file?name=[path][name].[ext]&context=./app/static"
}
]
}
};
in your js file :
require.context("./static/", true, /^\.\/.*\.html/);
./static/ is relative to where your js file is.
You can do the same with images or whatever.
The context is a powerful method to explore !!
One advantage that the aforementioned copy-webpack-plugin brings that hasn't been explained before is that all the other methods mentioned here still bundle the resources into your bundle files (and require you to "require" or "import" them somewhere). If I just want to move some images around or some template partials, I don't want to clutter up my javascript bundle file with useless references to them, I just want the files emitted in the right place. I haven't found any other way to do this in webpack. Admittedly it's not what webpack originally was designed for, but it's definitely a current use case.
(#BreakDS I hope this answers your question - it's only a benefit if you want it)
Webpack 5 adds Asset Modules which are essentially replacements for common file loaders. I've copied a relevant portion of the documentation below:
asset/resource emits a separate file and exports the URL. Previously achievable by using file-loader.
asset/inline exports a data URI of the asset. Previously achievable by using url-loader.
asset/source exports the source code of the asset. Previously achievable by using raw-loader.
asset automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using url-loader with asset size limit.
To add one in you can make your config look like so:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
}
]
}
};
To control how the files get output, you can use templated paths.
In the config you can set the global template here:
// webpack.config.js
module.exports = {
...
output: {
...
assetModuleFilename: '[path][name].[hash][ext][query]'
}
}
To override for a specific set of assets, you can do this:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
generator: {
filename: '[path][name].[hash][ext][query]'
}
}
]
}
};
The provided templating will result in filenames that look like build/images/img.151cfcfa1bd74779aadb.png. The hash can be useful for cache busting etc. You should modify to your needs.
Above suggestions are good. But to try to answer your question directly I'd suggest using cpy-cli in a script defined in your package.json.
This example expects node to somewhere on your path. Install cpy-cli as a development dependency:
npm install --save-dev cpy-cli
Then create a couple of nodejs files. One to do the copy and the other to display a checkmark and message.
copy.js
#!/usr/bin/env node
var shelljs = require('shelljs');
var addCheckMark = require('./helpers/checkmark');
var path = require('path');
var cpy = path.join(__dirname, '../node_modules/cpy-cli/cli.js');
shelljs.exec(cpy + ' /static/* /build/', addCheckMark.bind(null, callback));
function callback() {
process.stdout.write(' Copied /static/* to the /build/ directory\n\n');
}
checkmark.js
var chalk = require('chalk');
/**
* Adds mark check symbol
*/
function addCheckMark(callback) {
process.stdout.write(chalk.green(' ✓'));
callback();
}
module.exports = addCheckMark;
Add the script in package.json. Assuming scripts are in <project-root>/scripts/
...
"scripts": {
"copy": "node scripts/copy.js",
...
To run the sript:
npm run copy
The way I load static images and fonts:
module: {
rules: [
....
{
test: /\.(jpe?g|png|gif|svg)$/i,
/* Exclude fonts while working with images, e.g. .svg can be both image or font. */
exclude: path.resolve(__dirname, '../src/assets/fonts'),
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
}]
},
{
test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=\d+\.\d+\.\d+)?$/,
/* Exclude images while working with fonts, e.g. .svg can be both image or font. */
exclude: path.resolve(__dirname, '../src/assets/images'),
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
},
}
]
}
Don't forget to install file-loader to have that working.
You can write bash in your package.json:
# package.json
{
"name": ...,
"version": ...,
"scripts": {
"build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
...
}
}
Most likely you should use CopyWebpackPlugin which was mentioned in kevlened answer. Alternativly for some kind of files like .html or .json you can also use raw-loader or json-loader. Install it via npm install -D raw-loader and then what you only need to do is to add another loader to our webpack.config.js file.
Like:
{
test: /\.html/,
loader: 'raw'
}
Note: Restart the webpack-dev-server for any config changes to take effect.
And now you can require html files using relative paths, this makes it much easier to move folders around.
template: require('./nav.html')
I was stuck here too. copy-webpack-plugin worked for me.
However, 'copy-webpack-plugin' was not necessary in my case (i learned later).
webpack ignores root paths
example
<img src="/images/logo.png'>
Hence, to make this work without using 'copy-webpack-plugin'
use '~' in paths
<img src="~images/logo.png'>
'~' tells webpack to consider 'images' as a module
note:
you might have to add the parent directory of images directory in
resolve: {
modules: [
'parent-directory of images',
'node_modules'
]
}
Visit https://vuejs-templates.github.io/webpack/static.html
The webpack config file (in webpack 2) allows you to export a promise chain, so long as the last step returns a webpack config object. See promise configuration docs. From there:
webpack now supports returning a Promise from the configuration file. This allows to do async processing in you configuration file.
You could create a simple recursive copy function that copies your file, and only after that triggers webpack. E.g.:
module.exports = function(){
return copyTheFiles( inpath, outpath).then( result => {
return { entry: "..." } // Etc etc
} )
}
lets say all your static assets are in a folder "static" at the root level and you want copy them to the build folder maintaining the structure of subfolder, then
in your entry file) just put
//index.js or index.jsx
require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
In my case I used webpack for a wordpress plugin to compress js files, where the plugin files are already compressed and need to skip from the process.
optimization: {
minimize: false,
},
externals: {
"jquery": "jQuery",
},
entry: glob.sync('./js/plugin/**.js').reduce(function (obj, el) {
obj[path.parse(el).name] = el;
return obj
}, {}),
output: {
path: path.resolve(__dirname, './js/dist/plugin'),
filename: "[name].js",
clean: true,
},
That used to copy the js file as it is to the build folder. Using any other methods like file-loader and copy-webpack create issues with that.
Hope it will help someone.
Here is my project structure:
cloudRun
distApp // TRANSPILED APP FILES FROM ./src
distService // TRANSPILED BACKEND FILES FROM ./cloudRun/src
src // SOURCE FILES FOR THE BACKEND CODE
index.js // INDEX.JS FOR THE BACKEND CODE
babel.config.js // CONFIG FOR THE BABEL TRANSPILE SCRIPT
src // SOURCE FILES FOR THE APP
index.js // INDEX.JS FOR THE APP CODE
package.json // THIS IS THE MAIN PROJECT package.json
I'll try to be very succinct and clear.
In both of the index.js (app and backend code) I use path aliases in the source code.
For example:
./src/some-folder/some-file.js
import xxx from "#src/hooks/someHoot";
// IN THE TRANSPILED VERSION #src MUST BE CONVERTED TO ./cloudRun/distApp
And also, for example:
./cloudRun/src/some-folder/some-file.js
import xxx from "#src/hooks/someHoot";
// IN THE TRANSPILED VERSION #src MUST BE CONVERTED TO ./cloudRun/distApp
But somehow I'm having trouble when configuring module-resolver on babel.config.js. Either I get it to work correctly with the path aliases present on ./src (and path aliases on ./cloudRun/src are all wrong by 1 level) or vice-versa.
For example:
.cloudRun/babel.config.js
plugins = [
["module-resolver", {
"alias": {
"#src" : "./distApp",
"#hooks" : "./distApp/hooks",
}
}]
];
This works for the ./src files. But files from ./cloudRun/src are all wrong by 1 level up.
And if I change to this:
.cloudRun/babel.config.js
plugins = [
["module-resolver", {
"alias": {
"#src" : "./cloudRun/distApp",
"#hooks" : "./cloudRun/distApp/hooks",
}
}]
];
Then it works fine for the ./cloudRun/src files. But all files from ./src will be wrong by 1 level down.
I was thinking that I might fix this with the "root" option in the module-resolver config. But I couldn't make it work yet.
Maybe something like this:
.cloudRun/babel.config.js
plugins = [
["module-resolver", {
"root": ["./cloudRun"], // SET A NEW ROOT HERE
"alias": {
"#src" : "./distApp",
"#hooks" : "./distApp/hooks",
}
}]
];
I've tried many things inside the "root" config. But so far it doesn't seem to make any difference.
Here is how I run babel:
// SCRIPTS FROM ./package.json
babel src --out-dir cloudRun/distApp --config-file ./cloudRun/babel.config.js
babel cloudRun/src --out-dir cloudRun/distService --config-file ./cloudRun/babel.config.js
I have a file in my project called test.js
I don't import/require it anywhere which means my webpack won't call babel-loader for that js file.
Question: what I want is to move test.js into /dist folder, but as a compiled/transpiled. What's the best practice for it?
What I tried: I tried to use a copy-webpack-plugin and use its transform parameters before copying the file, but I can't seem to find the good babel package.
{
from: 'test.js',
to: '/dist/test.js',
transform(content, path) {
//what do I write here?
},
}
The simplest approach I could think about is to use several entry points like this:
{
entry: {
a: "./your-main-stuff",
b: "./your-single-file",
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].js"
}
}
which will create your a.js main bundle and b.js file in __dirname/dist folder both transpiled provided you used corresponding loader(s).
And from copy-webpack-plugin docs section:
webpack-copy-plugin is not designed to copy files generated from the
build process; rather, it is to copy files that already exist in the
source tree, as part of the build process.
so it seems to be difficult (if possible) making it move transpiled files.
Update. If you want to output files into different folders w/o changing your src folder, additonal tools needed. For your case (just 1 file) I would write a simple script and add it into package.json script section combined with webpack call like:
"scripts": {
"dev": "webpack && babel path-to-script.js --out-file path-to-script-compiled.js"
}
Just like in the previous answer, initially I went with the "scripts" entry in package.json that runs babel. But for a number of reasons I wanted to use webpack 5 to do the job. So after failing with webpack-copy-plugin and a good amount of digging around I came to this solution:
let config = {
entry: [
glob.sync(srcDir + '/**/*.js') // get all .js files from the source dir
],
output : {
filename : '[name].rem.js', // webpack wants to bundle - it can bundle here ;)
path: outDir
},
resolve: {
alias: {
'app': appDir
}
},
plugins: [
new RemoveEmptyScriptsPlugin({extensions: ['js'], scriptExtensions: /\.rem\.js/}) // for all .js source files that get bundled remove the bundle .rem.js file
],
module: {
rules:[{
test: /\.jsx?$/,
type: 'asset/resource', // get webpack to take it out instead of bundling
generator: {
filename: ({filename}) => filename // return full file name so directory structure is preserved
},
use: {
loader: 'babel-loader',
options: {
targets: { node: 16 },
presets: [
['#babel/preset-env', { modules: 'commonjs' /* transpile import/export */}],
]
}
}
}]
}
};
// Since the code does not go through the full pipeline and imports are not getting resolved, aliases will remain in the code.
// To resolve them it takes to hack the aliases object into the babel config
config.module.rules[0].use.options.plugins.push(['babel-plugin-webpack-alias-7', {config: {resolve: {alias: config.resolve.alias}}}];
And it does a good job but beware that it takes to use the patched versions of the two plugins (unless the patches have been merged already)!
Let's say I'm using webpack 4 and have a project that looks like this:
/src/index.js
const Important = "Important Text"
export default Important
global.important = Important
I compile it using the following webpack confing:
output: {
libraryTarget: 'commonjs2',
},
module: {
rules: [
{ ...babelConfig }
]
}
And the package.json has:
{
...packageJsonContents
"name": "important-project",
"main": "./dist/main.js",
}
This will create the minified file /dist/main.js
I save that plugin to npm as testproject
Now I create another project, configure Webpack and npm install important-project.
In the /src/index.js:
import Important from 'important-project'
console.log(Important) //prints "Important Text"
This works, however my goal is for this to be a general use plugin and I want to also be able to include it as a script tag in other projects, however when I include it as a script tag, it complains that module is not defined.
<script src="node_modules/important-project/dist/main.js"></script>
What's the conventional approach here? Should I create two builds? One for in html, and another for in webpack?
I'm trying to move from Gulp to Webpack. In Gulp I have task which copies all files and folders from /static/ folder to /build/ folder. How to do the same with Webpack? Do I need some plugin?
Requiring assets using the file-loader module is the way webpack is intended to be used (source). However, if you need greater flexibility or want a cleaner interface, you can also copy static files directly using my copy-webpack-plugin (npm, Github). For your static to build example:
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
context: path.join(__dirname, 'your-app'),
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: 'static' }
]
})
]
};
Compatibility note: If you're using an old version of webpack like webpack#4.x.x, use copy-webpack-plugin#6.x.x. Otherwise use latest.
You don't need to copy things around, webpack works different than gulp. Webpack is a module bundler and everything you reference in your files will be included. You just need to specify a loader for that.
So if you write:
var myImage = require("./static/myImage.jpg");
Webpack will first try to parse the referenced file as JavaScript (because that's the default). Of course, that will fail. That's why you need to specify a loader for that file type. The file- or url-loader for instance take the referenced file, put it into webpack's output folder (which should be build in your case) and return the hashed url for that file.
var myImage = require("./static/myImage.jpg");
console.log(myImage); // '/build/12as7f9asfasgasg.jpg'
Usually loaders are applied via the webpack config:
// webpack.config.js
module.exports = {
...
module: {
loaders: [
{ test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/, loader: "file" }
]
}
};
Of course you need to install the file-loader first to make this work.
If you want to copy your static files you can use the file-loader in this way :
for html files :
in webpack.config.js :
module.exports = {
...
module: {
loaders: [
{ test: /\.(html)$/,
loader: "file?name=[path][name].[ext]&context=./app/static"
}
]
}
};
in your js file :
require.context("./static/", true, /^\.\/.*\.html/);
./static/ is relative to where your js file is.
You can do the same with images or whatever.
The context is a powerful method to explore !!
One advantage that the aforementioned copy-webpack-plugin brings that hasn't been explained before is that all the other methods mentioned here still bundle the resources into your bundle files (and require you to "require" or "import" them somewhere). If I just want to move some images around or some template partials, I don't want to clutter up my javascript bundle file with useless references to them, I just want the files emitted in the right place. I haven't found any other way to do this in webpack. Admittedly it's not what webpack originally was designed for, but it's definitely a current use case.
(#BreakDS I hope this answers your question - it's only a benefit if you want it)
Webpack 5 adds Asset Modules which are essentially replacements for common file loaders. I've copied a relevant portion of the documentation below:
asset/resource emits a separate file and exports the URL. Previously achievable by using file-loader.
asset/inline exports a data URI of the asset. Previously achievable by using url-loader.
asset/source exports the source code of the asset. Previously achievable by using raw-loader.
asset automatically chooses between exporting a data URI and emitting a separate file. Previously achievable by using url-loader with asset size limit.
To add one in you can make your config look like so:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
}
]
}
};
To control how the files get output, you can use templated paths.
In the config you can set the global template here:
// webpack.config.js
module.exports = {
...
output: {
...
assetModuleFilename: '[path][name].[hash][ext][query]'
}
}
To override for a specific set of assets, you can do this:
// webpack.config.js
module.exports = {
...
module: {
rules: [
{
test: /\.(jpe?g|gif|png|svg|woff|ttf|wav|mp3)$/,
type: "asset/resource"
generator: {
filename: '[path][name].[hash][ext][query]'
}
}
]
}
};
The provided templating will result in filenames that look like build/images/img.151cfcfa1bd74779aadb.png. The hash can be useful for cache busting etc. You should modify to your needs.
Above suggestions are good. But to try to answer your question directly I'd suggest using cpy-cli in a script defined in your package.json.
This example expects node to somewhere on your path. Install cpy-cli as a development dependency:
npm install --save-dev cpy-cli
Then create a couple of nodejs files. One to do the copy and the other to display a checkmark and message.
copy.js
#!/usr/bin/env node
var shelljs = require('shelljs');
var addCheckMark = require('./helpers/checkmark');
var path = require('path');
var cpy = path.join(__dirname, '../node_modules/cpy-cli/cli.js');
shelljs.exec(cpy + ' /static/* /build/', addCheckMark.bind(null, callback));
function callback() {
process.stdout.write(' Copied /static/* to the /build/ directory\n\n');
}
checkmark.js
var chalk = require('chalk');
/**
* Adds mark check symbol
*/
function addCheckMark(callback) {
process.stdout.write(chalk.green(' ✓'));
callback();
}
module.exports = addCheckMark;
Add the script in package.json. Assuming scripts are in <project-root>/scripts/
...
"scripts": {
"copy": "node scripts/copy.js",
...
To run the sript:
npm run copy
The way I load static images and fonts:
module: {
rules: [
....
{
test: /\.(jpe?g|png|gif|svg)$/i,
/* Exclude fonts while working with images, e.g. .svg can be both image or font. */
exclude: path.resolve(__dirname, '../src/assets/fonts'),
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'images/'
}
}]
},
{
test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=\d+\.\d+\.\d+)?$/,
/* Exclude images while working with fonts, e.g. .svg can be both image or font. */
exclude: path.resolve(__dirname, '../src/assets/images'),
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
},
}
]
}
Don't forget to install file-loader to have that working.
You can write bash in your package.json:
# package.json
{
"name": ...,
"version": ...,
"scripts": {
"build": "NODE_ENV=production npm run webpack && cp -v <this> <that> && echo ok",
...
}
}
Most likely you should use CopyWebpackPlugin which was mentioned in kevlened answer. Alternativly for some kind of files like .html or .json you can also use raw-loader or json-loader. Install it via npm install -D raw-loader and then what you only need to do is to add another loader to our webpack.config.js file.
Like:
{
test: /\.html/,
loader: 'raw'
}
Note: Restart the webpack-dev-server for any config changes to take effect.
And now you can require html files using relative paths, this makes it much easier to move folders around.
template: require('./nav.html')
I was stuck here too. copy-webpack-plugin worked for me.
However, 'copy-webpack-plugin' was not necessary in my case (i learned later).
webpack ignores root paths
example
<img src="/images/logo.png'>
Hence, to make this work without using 'copy-webpack-plugin'
use '~' in paths
<img src="~images/logo.png'>
'~' tells webpack to consider 'images' as a module
note:
you might have to add the parent directory of images directory in
resolve: {
modules: [
'parent-directory of images',
'node_modules'
]
}
Visit https://vuejs-templates.github.io/webpack/static.html
The webpack config file (in webpack 2) allows you to export a promise chain, so long as the last step returns a webpack config object. See promise configuration docs. From there:
webpack now supports returning a Promise from the configuration file. This allows to do async processing in you configuration file.
You could create a simple recursive copy function that copies your file, and only after that triggers webpack. E.g.:
module.exports = function(){
return copyTheFiles( inpath, outpath).then( result => {
return { entry: "..." } // Etc etc
} )
}
lets say all your static assets are in a folder "static" at the root level and you want copy them to the build folder maintaining the structure of subfolder, then
in your entry file) just put
//index.js or index.jsx
require.context("!!file?name=[path][name].[ext]&context=./static!../static/", true, /^\.\/.*\.*/);
In my case I used webpack for a wordpress plugin to compress js files, where the plugin files are already compressed and need to skip from the process.
optimization: {
minimize: false,
},
externals: {
"jquery": "jQuery",
},
entry: glob.sync('./js/plugin/**.js').reduce(function (obj, el) {
obj[path.parse(el).name] = el;
return obj
}, {}),
output: {
path: path.resolve(__dirname, './js/dist/plugin'),
filename: "[name].js",
clean: true,
},
That used to copy the js file as it is to the build folder. Using any other methods like file-loader and copy-webpack create issues with that.
Hope it will help someone.