How do I generate SVG sprites with GatsbyJS - javascript

In my gatsby-browser.js file, I have two imports that look similar to:
#import npm-package/lib/icons.svg
#import npm-package/lib/icons-rich.svg
My current gatsby-node.js file is as follows
const path = require('path')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin')
exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
const config = getConfig()
config.resolve.alias = {
...config.resolve.alias,
/// aliases working fine
}
config.module.rules = [
...config.module.rules,
{
test: /(icons|icons-rich).svg$/,
loader: 'svg-sprite-loader',
options: {
extract: true,
publicPath: './'
},
},
],
config.plugins = [
...config.plugins,
new SpriteLoaderPlugin()
]
actions.replaceWebpackConfig(config)
}
When I run gatsby develop, I get the following error:
Module Warning (from ./node_modules/svg-sprite-loader/lib/loader.js):
svg-sprite-loader exception. Some loaders will be applied after svg-sprite-loader in extract mode
and no files are ever output.
When i run gatsby build, I get a sprite.svg file output to the public directory but it doesn't seem like the svg sprite gets added to the html document body.
1) How do I get the gatsby develop command to process and output the svg to the proper directory
2) I suspect the issue with gatsby build is related to the svg file i'm trying include in the html document, which is in my Layout.jsx file and looks like
<Icon icon="all" iconPath="./public/sprite.svg" />
I would guess the ./public/sprite.svg is missing for some reason but I can't figure out what the correct file path is (tried everything except the right thing apparently).

Related

next-images Error: Module parse failed: Unexpected character '�'

I'm trying to load an image with next-images:
when i type in the image name it works fine:
//Working
<Image src={require(`../../images/exampleImage.jpg` )}/>
but i dont want that i want dynamic url like this:
//Not working
<img src={require(`../../images/${image}.jpg` )}/>
i get this error:
Error: Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)
my next.config.js file:
const withImages = require("next-images");
module.exports = withImages();
i also tried this config:
module.exports = {
webpack: (config, options) => {
config.module.rules.push(
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: 'url-loader?limit=100000'
}
)
return config
},
}
I tried many methods but none seems to work please help, thanks
If you're open to using the file-loader library to handle images on the project. You could install the library and set the rules like this on webpack:
...
config.module.rules.push(
{
test: /\.(png|jpeg|jpg|gif|svg)$/,
use: {
loader: "file-loader"
},
}
),
You can read more about file-loader from its documentation on webpack
Webpack is most likely trying to find & include your images at the build time. This cannot work with reading the name from a variable. You have 2 options:
manage images differently
if you have a finite (or rather short) list of images, just import all & use some kind of switch to control which image is displayed.
I had this issue too.
delete all your code in the next.config.js
add the below codes instead:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
dangerouslyAllowSVG: true,
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
};
module.exports = nextConfig;
It resolved my problem.

Rollup : single html output

I'm trying to package my Svelte app into a single Html file output.
I've managed to get the desired output with a configuration based on that answer :
Output Single HTML File from Svelte Project
With "npm run dev" everything is fine with the first build, but I'm having issues following (live-reload) builds: bundle['bundle.css'] is not filled in my inlineSvelte's generateBundle function.
I didn't manage to change the rollup-plugin-css-only for rollup-plugin-embed-css, which seemed to have an appropriate name for my needs.
Here's my rollup.config.js :
import svelte from 'rollup-plugin-svelte';
import livereload from 'rollup-plugin-livereload';
import css from 'rollup-plugin-css-only';
...
function inlineSvelte(templatePath, dest) {
return {
name: 'Svelte Inliner',
generateBundle(opts, bundle) {
const file = path.parse(opts.file).base;
const jsCode = bundle[file].code;
const cssCode = bundle['bundle.css'].source;
const template = fs.readFileSync(templatePath, 'utf-8');
bundle[file].code = template
.replace('%%script%%', jsCode)
.replace('%%style%%', cssCode);
}
}
}
export default {
input: 'src/main.js',
output: {
format: 'es',
file: outputDir + 'index.html',
name: 'app'
},
plugins: [
svelte({
compilerOptions: {
dev: !production
}
}),
css({ output: 'bundle.css' }),
resolve({
browser: true,
dedupe: ['svelte']
}),
commonjs(),
!production && livereload(outputDir),
inlineSvelte('./src/template.html')
],
watch: {
clearScreen: false
}
};
It is surely possible to embed the produced CSS file in your HTML, at least with some reasonably simple custom plugin.
However, if you only have CSS in your Svelte components, that is you don't have import 'whatever.css' anywhere in your code, you can just rely on Svelte injecting CSS from compiled JS code and be done with it.
This loses a little in terms of performance because such injected CSS will never be cached by the browser, but it avoids the added complexity / risk / coupling associated with a custom build step... And this kind of performance is often not so important in scenarios where you want all your app in a single HTML file.
To enable this, set emitCss: false on the Svelte plugin:
plugins: [
svelte({
emitCss: false,
...
}),
...
],
...
You won't need any Rollup plugin for CSS in this case.

Storybook webpack absolute import

In our app we are using absolute paths for import modules. We have react folder into our resolve root:
Folder structure
We are using webpack for build and develop app and it works ok, with the next options:
resolve: {
modules: [
'node_modules',
path.resolve('src')
]
},
I'm working on integration of storybook and found, that it can't find any module from this react folder.
ERROR in ./stories/index.stories.js
Module not found: Error: Can't resolve 'react/components/Button' in 'project_name/stories'
# ./stories/index.stories.js
for the next line:
import Button from 'react/components/Button';
As mark: I added resolve/modules to .storybook/webpack config and also if I try to import anything other from, for example services/xxx - it works.
Issues
react folder name conflicts with actual React package location: node_modules/react. Webpack tries to resolve to .resolution(default is node_modules) if the file does not exist in the path.
.resolution is not appropriate for this sort of usage. it is mostly used for package resolution because it can't tell source strings.
to change path selectively, use alias instead.
Solution
change your component folder's name so that it does not collide with node_modules/react. a good example is view/components/Button.
add alias to .storybook/main.js setting
// .storybook/main.js
const path = require('path');
module.exports = {
/* ... other settings goes here ... */
/**
* #param {import('webpack').Configuration} config
* */
webpackFinal: async (config, { configType }) => {
if (!config.resolve) config.resolve = {};
// this config allows to resolve `view/...` as `src/view/...`
config.resolve.alias = {
...(config.resolve.alias || {}),
view: path.resolve(__dirname, '../src/view'),
};
return config;
},
};
change storybook code in accordance with (1)
// Button.stories.jsx
import Button from 'view/components/Button';
//...

Vue js babel build error after installing prerender-spa-plugin

So I have a vue-js application and today I started using prerender-spa-plugin to generate some static pages for better SEO. When I run npm run build, everything works perfect, no errors. Now when I want to run the development server with npm run serve, I get the following error (only a part of it)
error in ./src/main.js
Module build failed (from ./node_modules/babel-
loader/lib/index.js):
Error: .plugins[0] must include an object
at assertPluginItem (/Users/user/Desktop/app/node_modules/#babel/core/lib/config/validation/option-assertions.js:231:13)
So I guess the problem has to do with the babel plugin loader. So I commended every part of my code using prerender-spa-plugin, but I still get the same error. I hope someone can point me to the right direction.
My babel.config.js
const removeConsolePlugin = []
if(process.env.NODE_ENV === 'production') {
removeConsolePlugin.push("transform-remove-console")
}
module.exports = {
presets: [
'#vue/app'
],
plugins: [removeConsolePlugin]
}
My vue.config.js
const path = require('path');
const PrerenderSpaPlugin = require('prerender-spa-plugin');
const productionPlugins = [
new PrerenderSpaPlugin({
staticDir: path.join(__dirname, 'dist'),
routes: ['/', '/documentation'],
renderer: new PrerenderSpaPlugin.PuppeteerRenderer({
// We need to inject a value so we're able to
// detect if the page is currently pre-rendered.
inject: {},
// Our view component is rendered after the API
// request has fetched all the necessary data,
// so we create a snapshot of the page after the
// `data-view` attribute exists in the DOM.
//renderAfterElementExists: '[data-view]',
}),
}),
];
module.exports = {
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(...productionPlugins);
}
}
}

Skipping entry with js files in WebPack

I have to use Webpack for one of my projects to build front-end bundles for js, css and other static assets. It does the job well, but in my early stages of the project I've got only some css and static images and no js files yet. Here is my full webpack.config.js
const Webpack = require("webpack");
const Glob = require("glob");
const path = require("path");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const configurator = {
entries: function(){
var entries = {
application: [
'./assets/dummy.js',
],
}
return entries
},
plugins() {
var plugins = [
new CopyWebpackPlugin([{from: "./assets",to: ""}], {copyUnmodified: true,ignore: ["css/**", "js/**", "**.js"] }),
];
return plugins
},
moduleOptions: function() {
return {
rules: [
]
}
},
buildConfig: function(){
const env = process.env.NODE_ENV || "development";
var config = {
mode: env,
entry: configurator.entries(),
output: {filename: "[name].[hash].js", path: `${__dirname}/public/assets`},
plugins: configurator.plugins(),
module: configurator.moduleOptions()
}
return config
}
}
module.exports = configurator.buildConfig()
Practically what it does for me is copying assets to public dir. I don't have any javascripts yet, but they will be in the future. So, I tried commenting entry, setting it to null or empty string with no luck. It seems Webpack needs to process js files so badly. My current solution is creating an empty dummy.js file and feeding it to Webpack. Annoyingly it generates some 3.3kb application.afff4a3748b8d5d33a3a.js file with some boilerplate js code, despite that my source js file is totally empty.
I understand that this is an edge use case for Webpack and Webpack was primarily created for processing javascript, but I bet many people still use it not just for bundling javascripts. So, my question, is there a better, more elegant way to skip bundling js files in Webpack?
p.s.
I think, I've found a related question without an answer here How to make WebPack copy a library instead of bundling?
p.s.#2
The suggested duplicate question has an accepted answer with an invalid Webpack config Invalid configuration object., so, I can't use it to solve my issue.
Moreover, the answer reads
webpack will create a dummy javascript file
and I'm specifically asking how to avoid creating unnecessary files.

Categories