How to copy sitemap.xml to build folder with React & Webpack? - sitemap

I have a sitemap.xml file in public folder. When I build the React application, the sitemap.xml file is not present in the dist/build folder.
What Webpack configuration is needed to achieve that? How does robots.txt need to be set up?

Here is the webpack-config for serving a file to build folder witha a custom name
module: {
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
},
],
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(?:ico|gif|png|jpg|jpeg|xml)$/i,
type: 'asset/resource',
},
{
test: /\.xml/,
type: 'asset/resource',
generator: {
filename: 'sitemap.xml',
},
},
{
test: /\.txt/,
type: 'asset/resource',
generator: {
filename: 'robots.txt',
},
},
{
test: /\.(woff(2)?|eot|ttf|otf|svg|)$/,
type: 'asset/inline',
},
],
},
Finally make sure you import that file inside your react application or else it will not be served to build folder

Related

npm run watch/hot only successful on the first run

Background:
I added TypeScript support to my existing project, so I added ts-loader and typescript. I think, I configured everything right and it is working fine in dev and prod mode.
I would like to update gradually, keeping all the JavaScript code in place and using TypeScript for everything new or where there is a need for refactoring. So it may be important to note that TableValue.vue is an old js component.
Problem:
Edit: It also occurs with npm run watch
When I run npm run hot in package.json: "scripts": { ..., "hot": "mix watch --hot", ...} it only works on the first try. As soon as I change any file and trigger a recompile, I get:
√ Mix: Compiled successfully in 19.15s
webpack compiled successfully
// Here the recompile is triggered
i Compiling Mix
√ Mix: Compiled with some errors in 509.01ms
ERROR in C:\fakepath\resources\js\components\test\component.vue.ts
24:23-41
[tsl] ERROR in C:\fakepath\resources\js\components\test\component.vue.ts(24,24)
TS2307: Cannot find module './TableValue.vue' or its corresponding type declarations.
webpack compiled with 1 error
I suspect that this error comes from ts-loader, but why is everything working on the first try?
I could just ignore this error, but then hot module replacement is unusable, because I have to manually trigger a new build process every time anyway.
Has someone got such an setup working?
What can I do to solve this error?
Infos:
I'm working with:
Laravel 8.58
Laravel Mix 6.0.25
Vue 2.6.14
ts-loader 9.2.5
typescript 4.4.2
Here the script tag from the test component:
<script lang="ts">
import Vue, { PropType } from 'vue';
import TableValue from "./TableValue.vue";
import Model from "#/js/types/model.js";
export default Vue.extend({
name: "TestComponent",
components: {
TableValue
},
props: {
'model': {
type: Object as PropType<Model>,
required: true
}
},
data() {
return {};
},
});
</script>
Project Structure:
app/
bootstrap/
config/
database/
node_modules/
public/
resources/
js/
components/
store/
types/
views/
app.js
bootstrap.js
routes.js
shims-vue.d.ts
lang/
sass/
views/
routes/
storage/
tests/
vendor/
composer.json
composer.lock
tsconfig.json
package-lock.json
package.json
phpunit.xml
vs.code-workspace
webpack.mix.js
webpack.mix.js:
const mix = require('laravel-mix');
const ResolveTypeScriptPlugin = require("resolve-typescript-plugin").default;
mix.webpackConfig({
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
options: { appendTsSuffixTo: [/\.vue$/] },
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.js', '.ts', '.vue'],
alias: {
'#': __dirname + '/resources'
},
fullySpecified: false,
plugins: [new ResolveTypeScriptPlugin()]
},
devtool: 'source-map'
}).sourceMaps();
mix.ts('resources/js/app.js', 'public/js')
.sass('resources/sass/app.sass', 'public/css').sourceMaps()
.vue();
mix.extract();
tsconfig.json:
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"noImplicitAny": false,
"importHelpers": true,
"moduleResolution": "node",
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"allowJs": true,
"checkJs": false,
"sourceMap": true,
"baseUrl": ".",
"paths": {
"#/*": [
"resources/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"files": [
"resources/js/shims-vue.d.ts"
],
"include": [
"resources/js/**/*.ts",
"resources/js/**/*.vue",
],
"exclude": [
"node_modules",
".vscode",
"app",
"bootstrap",
"config",
"database",
"public",
"routes",
"storage",
"tests",
"vendor"
]
}
Update:
When I remove shims-vue.d.ts, I get the error immediately.
declare module "*.vue" {
import Vue from "vue";
export default Vue;
}
It looks like this file is only read/applyed once and not after? Not sure.
It looks like ts-loader doesn't support HMR yet.
https://github.com/TypeStrong/ts-loader#hot-module-replacement
I installed fork-ts-checker-webpack-plugin and updated webpack.mix.js to:
const mix = require('laravel-mix');
const path = require('path');
const ResolveTypeScriptPlugin = require("resolve-typescript-plugin").default;
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
mix.webpackConfig({
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true
},
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.js', '.ts', '.tsx', '.vue'],
alias: {
'#': path.resolve(__dirname + '/resources'),
'#store': path.resolve(__dirname + '/resources/js/store'),
'#components': path.resolve(__dirname + '/resources/js/components')
},
fullySpecified: false,
plugins: [new ResolveTypeScriptPlugin()]
},
plugins: [new ForkTsCheckerWebpackPlugin()],
devtool: 'source-map'
}).sourceMaps();
mix.ts('resources/js/app.js', 'public/js')
.sass('resources/sass/app.sass', 'public/css').sourceMaps()
.vue();
mix.extract();
Now everything is working fine but I'm still not sure why watch was also affected and where exactly the problem was.
I'm not using Typescript, but the same thing was happening to me, when i ran npm run watch/hot where only successful on the first change of the code, then, you can not see the changes until you run npm run watch/hot or npm run dev again. The strange thing was that everything was compiling successfully on every change I made.
I manage to debug it with git, and found out that I was importing a component with a wrong name but did not get an error on the console.
My component name was WhosApplying.vue
I got:
import WhosApplying from "#/whosApplying.vue"
And change it for:
import WhosApplying from "#/WhosApplying.vue";
That mistake in the w instead of W make me lose hours. 😅
I ran into this using laravel-mix after adding typescript to an Inertia / Vue 3 project.
Using Volar (Not Vuter)
To fix it I changed my webpack.config.js file from:
const path = require('path');
module.exports = {
resolve: {
alias: {
'#': path.resolve('resources/js'),
},
},
};
to:
const path = require('path');
module.exports = {
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader",
options: {
appendTsSuffixTo: [/\.vue$/],
transpileOnly: true
},
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.js', '.ts', '.tsx', '.vue'],
alias: {
'#': path.resolve(__dirname + '/resources/js'),
},
},
};

How to base64 images using webpack?

I am using https://github.com/wbkd/webpack-starter for my project
I do have svg and png images that referenced in my html file like <img src="/public/image.png"/>
Instead of loading image using src path I want to inject image as base64 content to my html file to improve the page performance and to minify the number of server requests.
So I wonder how would you do that?
UPDATE:
here is what I did, but that does not work
npm install url-loader --save-dev
and add this configuration to production config:
module: {
rules: [
{
test: /\.(png|jpg|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: false,
},
},
],
},
]
}
I tried to play with limit values but won't help.
Any ideas ?
UPDATE:
that is my current rules config, but nothing works, I also installed html-loader but no effect:
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
{
test: /\.s?css/i,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader',
],
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: false,
},
},
],
},
{
test: /\.html$/i,
loader: 'html-loader',
},
],
Here's a few steps you should follow to sort your problem out:
Add html-loader to your webpack.config.prod.js:
webpack.config.prod.js
{
test: /\.html$/i,
loader: 'html-loader',
},
Fix your src of your <img /> to use the relative path instead of absolute path which doesn't work:
<img src="../public/image.png"/> // this is incorrect `/public/image.png`
Finally, add a publicPath to output in webpack.common.js to make it work properly with html-webpack-plugin:
webpack.common.js
{
output: {
// ...
publicPath: '/',
},
}
Make sure to set url-loader litmit to true. According to their docs, setting it to true is the default option and there's no limit to a file's size to be transformed into base64.
Setting it to false will not transform images to base64.
module: {
rules: [
{
test: /\.(png|jpg|gif|svg)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: true,
},
},
],
},
]
}
Also, in order for images to be handled by webpack, you need to import them.
import MyImage from '../public/image.png'

Gatsby doesn't build images to public

I'm making a basic site with gatsby, but can't get images to work.
In markdown content/projects/askj/index.md file I have:
![livechat](./livechat.png)
and I placed an image also into that directory.
In gatsby-config I have:
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/content`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-transformer-remark`,
options: {
plugins: [
{
resolve: `gatsby-remark-images`,
options: {
maxWidth: 590,
},
},
'gatsby-remark-prismjs',
'gatsby-remark-copy-linked-files',
],
},
},
but the images do not end up getting copied into the /public rendered version of the site.
I've tried various other combinations of paths and options, but I think I'm missing something.
I did put some png files into /images and they get copied across and can be ref'd, but I want to put the images into each directory with the respective content markdown.
Thanks for ideas!
refs:
- https://codebushi.com/gatsby-featured-images/
- https://www.orangejellyfish.com/blog/a-comprehensive-guide-to-images-in-gatsby/
- https://www.gatsbyjs.org/packages/gatsby-remark-images/?=remark

Webpack sass to css specify a specific folder?

I've been looking over the docs and checking other people's questions but I can't find the simple answer to how to compile all my sass down to a simple css file and specify the directory I want the resulting css file to output to.
For quick context:
I have a public directory with a stylesheets directory and a build directory in it. webpack compiles the app into build, and I'd like to have the sass compile style.css into the stylesheets directory.
Here's a screenshot of my public directory:
public dir img
I'd like to be able to do something like this in my webpack.config.js (only showing pertinent code for brevity):
const ExtractTextPlugin = require('extract-text-webpack-plugin');
...
// To be called in plugins:
const cssOutput = new ExtractTextPlugin('./public/stylesheets/style.css');
inside module loaders:
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract('style-loader', 'css-loader!sass-loader'),
},
In plugins:
plugins: [
.
.
.
cssOutput,
],
I'd like to be able to access the output file with this line in my index.html file located in the public directory:
<link rel="stylesheet" href="/stylesheets/style.css" />
I'm currently doing this using gulp and it works fine, I'm just trying to transition everything into webpack. Any help would be greatly appreciated!
Turns out you can just set the output file like this:
const cssOutput = new ExtractTextPlugin('../stylesheets/style.css', { allChunks: true });
I made the noob mistake of forgetting to add:
require('_scss/style.scss');
in my index.jsx file.
For anyone who runs into this issue, I still had trouble with fonts and images, so inside module loaders in the webpack.config.js I had to add:
{
test: /\.(eot|woff|woff2|ttf|svg|png|jpe?g|gif)(\?\S*)?$/,
loader: 'file',
},
and since this output everything into my build directory, I just changed the css to output everything in the build directory as well to prevent path errors. I changed it to this:
const cssOutput = new ExtractTextPlugin('style.css', { allChunks: true });
Hopefully this helps someone else who runs into this type of issue!
Work for Me::
webpack.config.js
module.exports = {
entry: ['./src/app.ts', './src/sass/style.scss'],
module:{
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
include: [path.resolve(__dirname, 'src', 'src/class')]
},
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: '/css/[name].css'
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader?-url'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
],
include: [path.resolve(__dirname, 'src/sass')]
}
]
},
output: {
filename: 'js/app.js',
path: path.resolve(__dirname, 'public')
}
}
postcss.config.js
module.exports = {
plugins: {
'autoprefixer': {}
}
}
package.json
{
"name": "tsscript",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"nov": "webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.8.5",
"css": "^3.0.0",
"css-loader": "^3.6.0",
"extract-loader": "^5.1.0",
"postcss-loader": "^3.0.0",
"sass": "^1.26.10",
"sass-loader": "^9.0.2",
"style-loader": "^1.2.1",
"ts-loader": "^8.0.0",
"typescript": "^3.9.6",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12"
}
}
Directory Snap:
Have you take a look at https://www.npmjs.com/package/extract-text-webpack-plugin?
you'll probably need it.
Recent solution, you can use mini-css-extract-plugin, css-loader, and sass-loader. mini-css-extract-plugin can create a CSS file per JS file which contains CSS.
Install dependencies:
npm i -D mini-css-extract-plugin css-loader sass-loader
For example, your main JS file that includes a style is ./src/index.js:
...
import './src/style.scss';
...
Configure webpack.config.js:
...
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
...
entry: {
main: './src/index.js',
},
plugins: [
new MiniCssExtractPlugin(),
],
...
module: {
rules: [
...
{
test: /\.s[ac]ss$/i,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader",
],
},
...
]
},
resolve: {
modules: ["node_modules", path.resolve(__dirname, "src")],
extensions: ['.js', '.scss', ...]
}
}
Then, you can check your output directory, there will be main.css. The plugin set default name to [name].css (entry name).

How grunt-scss-lint can exclude some files or directory?

I am using grunt-scss-lint with sucess.
but I wanna exclude a folder or files, but after runt he task still catching the folder, any idea how to exclude the file or directory?
in the docs says:
exclude
Type: String or Array
Default: null
Exclude one or more files from being linted.
grunt task
scsslint: {
allFiles: [
'scss/_main.scss',
],
options: {
config: 'scss/.scss-lint.yml',
reporterOutput: '.tmp/scss-lint-report.xml',
colorizeOutput: true,
compact:false,
},
exclude: [
'scss/vendor/font-awesome/font-awesome.scss'
]
},
any ideas?
Update:
fixed moving exclude to the options.
scsslint: {
allFiles: [
'scss/_main.scss',
],
options: {
config: 'scss/.scss-lint.yml',
reporterOutput: '.tmp/scss-lint-report.xml',
colorizeOutput: true,
compact:false,
exclude: [
'scss/vendor/font-awesome/font-awesome.scss'
]
}
},
The exclude configuration must be moved to within the options object:
options: {
config: 'scss/.scss-lint.yml',
reporterOutput: '.tmp/scss-lint-report.xml',
colorizeOutput: true,
compact:false,
exclude: [
'scss/vendor/font-awesome/font-awesome.scss'
]
},

Resources