React. Import svg - reactjs

Export svg from root file index.ts
import * as upArrow from "./up-arrow.svg";
import * as downArrow from "./down-arrow.svg";
export { upArrow, downArrow };
Try to use in my component
import * as React from "react";
import { Icon } from "components";
import { upArrow, downArrow } from "common/assets";
const CollapseIcon = ({ condition }) => (
<Icon alternative={upArrow} asset={downArrow} condition={condition} />
);
export default CollapseIcon;
If it's important, I use values asset and alternative in src attribute like that
export default styled.img.attrs<IconProps>({
src: ({ condition, alternative, asset }: IconProps) =>
condition ? alternative : asset,
alt: ({ alt }: IconProps) => alt
})`
vertical-align: middle;
`
But get html-element with double quotes. If delete it, element view correctly. Where am I wrong?
I try to declare non-code assets accrding docs, but never change
declare module "*.svg" {
const content: string;
export default content;
}
declare module "*.png";
declare module "*.jpg";
My Webpack config:
"use strict";
const path = require("path");
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
const InterpolateHtmlPlugin = require("react-dev-utils/InterpolateHtmlPlugin");
const WatchMissingNodeModulesPlugin = require("react-dev-utils/WatchMissingNodeModulesPlugin");
const ModuleScopePlugin = require("react-dev-utils/ModuleScopePlugin");
const getClientEnvironment = require("./env");
const paths = require("./paths");
const publicPath = "/";
const publicUrl = "";
const env = getClientEnvironment(publicUrl);
module.exports = {
devtool: "cheap-module-source-map",
entry: [
require.resolve("./polyfills"),
require.resolve("react-dev-utils/webpackHotDevClient"),
paths.appIndexJs
],
output: {
pathinfo: true,
filename: "static/js/bundle.js",
chunkFilename: "static/js/[name].chunk.js",
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")
},
resolve: {
modules: [paths.appSrc, paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: [".ts", ".tsx", ".js", ".jsx"],
alias: {
"react-native": "react-native-web"
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])
]
},
module: {
strictExportPresence: true,
rules: [
{
enforce: "pre",
test: /\.js$/,
loader: "source-map-loader"
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]"
}
},
{
test: /\.(ts|tsx|js|jsx)?$/,
loader: "awesome-typescript-loader",
options: {
getCustomTransformers: require("../config/transformers.js")
}
},
{
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
loader: require.resolve("file-loader"),
options: {
name: "static/media/[name].[hash:8].[ext]"
}
}
]
}
]
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)
],
node: {
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty"
},
performance: {
hints: false
},
externals: {
react: "React",
"react-dom": "ReactDOM"
},
devtool: "source-map"
};
UPD. As I see, browser receive my string as link

Add .svg extension to extenstions list for url-loader like that
...
rules: [
...
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]"
}
},
...

Related

What's best way to config React components library with Webpack, typescript, css modules and SASS

I'm config a React components library for reuses in other our projects. I want to use these:
Typescript for components
Css modules
Sass
Webpack for bundle
So this is my webpack config:
const childProcess = require('child_process');
const path = require('path');
const url = require('url');
const webpack = require('webpack');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const loadersConf = require('./webpack.loaders');
const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
const targetIsRun = NPM_TARGET === 'run';
const targetIsTest = NPM_TARGET === 'test';
const targetIsStats = NPM_TARGET === 'stats';
const targetIsDevServer = NPM_TARGET === 'dev-server';
const DEV = targetIsRun || targetIsStats || targetIsDevServer;
const STANDARD_EXCLUDE = [
path.join(__dirname, 'node_modules'),
];
// These files will be imported in every sass file
const sassResourcesPaths = [
path.resolve(__dirname, 'src/styles/abstracts/_variables.sass'),
path.resolve(__dirname, 'src/styles/abstracts/_mixins.sass'),
];
const config = {
module: {
rules: loadersConf,
},
resolve: {
modules: [
'node_modules',
path.resolve(__dirname),
],
extensions: ['.js', '.jsx', '.ts', '.tsx', '.css', '.scss'],
},
performance: {
hints: 'warning',
},
target: 'web',
plugins: [
new webpack.DefinePlugin({
COMMIT_HASH: JSON.stringify(childProcess.execSync('git rev-parse HEAD || echo dev').toString()),
}),
new MiniCssExtractPlugin({
filename: '[name].[contentHash].css',
chunkFilename: '[name].[contentHash].css',
}),
],
};
if (DEV) {
config.mode = 'development';
config.devtool = 'source-map';
}
const env = {};
if (DEV) {
} else {
env.NODE_ENV = JSON.stringify('production');
}
config.plugins.push(new webpack.DefinePlugin({
'process.env': env,
}));
module.exports = config;
And this is loaders for webpack:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const STANDARD_EXCLUDE = [
path.join(__dirname, 'node_modules'),
];
const NPM_TARGET = process.env.npm_lifecycle_event; //eslint-disable-line no-process-env
const targetIsRun = NPM_TARGET === 'run';
const targetIsTest = NPM_TARGET === 'test';
const targetIsStats = NPM_TARGET === 'stats';
const targetIsDevServer = NPM_TARGET === 'dev-server';
const DEV = targetIsRun || targetIsStats || targetIsDevServer;
// noinspection WebpackConfigHighlighting
module.exports = [
{
test: /\.(js|jsx|ts|tsx)?$/,
exclude: STANDARD_EXCLUDE,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// Babel configuration is in .babelrc because jest requires it to be there.
},
},
},
{
type: 'javascript/auto',
test: /\.json$/,
include: [
path.resolve(__dirname, 'i18n'),
],
exclude: [/en\.json$/],
use: [
{
loader: 'file-loader?name=i18n/[name].[hash].[ext]',
},
],
},
// ==========
// = Styles =
// ==========
// Global CSS (from node_modules)
// ==============================
{
test: /\.css/,
include: path.resolve(__dirname, "node_modules"),
use: [
MiniCssExtractPlugin.loader,
{
loader: "style-loader"
},
{
loader: 'css-loader'
}
]
},
{
test: /\.(sc|sa|c)ss$/,
exclude: /\.st.css$/, //This must appear before the "oneOf" property
use: [
MiniCssExtractPlugin.loader,
'style-loader',
'css-modules-typescript-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2,
modules: true,
camelCase: "dashes",
localIdentName: DEV
? '[name]__[local]___[hash:base64:5]'
: '_[hash:base64:5]',
},
},
{
loader: "postcss-loader",
options: {
sourceMap: "inline",
extract: true,
}
},
"sass-loader",
],
},
{
test: /\.(png|eot|tiff|svg|woff2|woff|ttf|gif|mp3|jpg)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'files/[hash].[ext]',
},
},
{
loader: 'image-webpack-loader',
options: {},
},
],
},
];
Babel config:
const config = {
presets: [
['#babel/preset-env', {
targets: {
chrome: 66,
firefox: 60,
edge: 42,
safari: 12,
},
modules: false,
corejs: 3,
useBuiltIns: 'usage',
shippedProposals: true,
}],
['#babel/preset-react', {
useBuiltIns: true,
}],
['#babel/typescript', {
allExtensions: true,
isTSX: true,
}],
],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-syntax-dynamic-import',
'#babel/proposal-class-properties',
'#babel/proposal-object-rest-spread',
'#babel/plugin-proposal-optional-chaining',
['module-resolver', {
root: ['./src', './test'],
}],
],
};
// Jest needs module transformation
config.env = {
test: {
presets: config.presets,
plugins: config.plugins,
},
};
config.env.test.presets[0][1].modules = 'auto';
module.exports = config;
This is a demo component of this library:
import React from 'react';
const styles = require('./style.scss');
type Props = {
children?: React.ReactNode;
openLeft?: boolean;
openUp?: boolean;
id?: string;
ariaLabel: string;
customStyles?: object;
}
export default class Button extends React.PureComponent<Props> {
public render() {
return (
<button className={styles.test}>
{this.props.children}
</button>
);
}
}
So, this is develop build command:
"build": "cross-env NODE_ENV=production webpack --display-error-details --verbose",
"run": "webpack --progress --watch",
when I using this library:
import ExampleComponent from 'mylibrary';
When I run BUILD or RUN command, the javascript is built, but not SCSS. So in my other project, the build throw an error:
can not find module './style.scss'
This error occur in ExampleComponent
Please tell me how to resolve it. Thanks you very much!
This is my webpack config for the styles part:
{
test: /\.s?css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
config: {
path: 'postcss.config.js'
}
}
},
{
loader: 'sass-loader'
},
]
}
and in my postcss.config.js:
module.exports = {
plugins: [
require('autoprefixer')
]
}

i18next + React + Webpack - getFixedT is not a function

I'm having some trouble with React, i18next and Webpack. I've tried many solutions, but none of them worked. When I try to build my application, it builds successfully. But, when I try to open it, the console shows an error. My webpack.config and the error stacktrace are below.
webpack.prod.config.js
const webpack = require('webpack');
const path = require('path');
const htmlWebpackPlugin = require("html-webpack-plugin")
const miniCSSExtractPlugin = require("mini-css-extract-plugin")
const terserPlugin = require("terser-webpack-plugin")
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
const cleanWebpackPlugin = require("clean-webpack-plugin")
const i18nPlugin = require("i18n-webpack-plugin")
const options = require("../src/controllers/i18n").options
const locales = require("../src/controllers/i18n/locales")
options.backend.loadPath = "." + options.backend.loadPath
const config = {
mode: "production",
output: {
path: path.resolve(__dirname, '../dist'),
publicPath: "./",
filename: 'bundle.js'
},
resolve: {
extensions: [" ", ".js", ".jsx"],
alias: {
"#components": path.resolve(__dirname, "../src/components"),
"#views": path.resolve(__dirname, "../src/views")
}
},
optimization: {
minimizer: [
new terserPlugin({
cache: true,
parallel: true,
include: /\.(js|jsx)$/
}),
new OptimizeCSSAssetsPlugin({})
]
},
module: {
rules: [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [{
loader: "babel-loader"
}, {
loader: "i18next-loader"
}]
},
{
test: /\.css$/,
use: [
miniCSSExtractPlugin.loader,
{
loader: "css-loader",
}
]
}, {
test: /\.(png|jpg|gif)$/,
use: [{
loader: 'file-loader?name=images/[hash].[ext]',
options: {
name: "assets/images/[hash].[ext]"
}
}]
}, {
test: /\.(ttf|woff(2)|eof|svg)$/,
use: [{
loader: "file-loader",
options: {
name: "assets/fonts/[hash].[ext]",
}
}]
}
],
},
plugins: [
new htmlWebpackPlugin({
template: path.join(__dirname, "..", "public", "index.html")
}),
new miniCSSExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new cleanWebpackPlugin("../dist/*", {
root: __dirname + "../",
allowExternal: true
}),
new i18nPlugin(locales,{
functionName: "t",
nested: true
},true)
]
};
module.exports = config;
The npm run build runs normally, no errors about i18next. Then, when I open the application, I got this error:
bundle.js:33 TypeError: r.getFixedT is not a function
at L (bundle.js:12)
at bundle.js:12
at Xo (bundle.js:33)
at Ia (bundle.js:33)
at qi (bundle.js:33)
at $i (bundle.js:33)
at jl (bundle.js:33)
at Cl (bundle.js:33)
at Pl (bundle.js:33)
at Ji (bundle.js:33)
Hope somebody can helps me.
I've found what was the problem. The i18next documentation says that I should run the init inside the webpack.config.js.
The Problem
My initial problem was loading the locales. The i18n couldn't find the files after the build, because the webpack doesn't recognize the i18n-xhr-backend requiring the .json files. After the build, there was no translation files. Then, I've tried to let webpack deal with the i18n, and I got another problem, on next paragraph.
The React needs the i18n instance to be add to the i18nextProvider. But, the way that I was doing it, there was no i18n instance to refence inside React. Then, it coudn't find the translation function or anything else. I've also found the i18nWebpackPlugin, but it also didn't solved my problem, because it don't give access to the i18n instance inside react. At the end, I had two unsolved problems.
The Solution
My solution was quite simple. I've created a new i18n config to the development env and let the webpack deal with the .json, copying it to a new folder after build. I'll let my webpack and i18n config files below. The steps were:
Bring i18n.init() back to i18n/index.js
Create different options for each environment
Configure webpack to copy translation files
Import the i18n instance on App.js again
Now, everything works like a charm.
OBS: To webpack recognize the .json files, you need to import it somewhere. I did inside the resources.js file.
webpack.prod.config.js
const webpack = require("webpack");
const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
const miniCSSExtractPlugin = require("mini-css-extract-plugin");
const terserPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const cleanWebpackPlugin = require("clean-webpack-plugin");
const config = {
mode: "production",
output: {
path: path.resolve(__dirname, "../dist"),
publicPath: "./",
filename: "bundle.js"
},
resolve: {
extensions: [" ", ".js", ".jsx"],
alias: {
"#components": path.resolve(__dirname, "../src/components"),
"#views": path.resolve(__dirname, "../src/views"),
"#static": path.resolve(__dirname, "../src/static")
}
},
optimization: {
minimizer: [
new terserPlugin({
cache: true,
parallel: true,
include: /\.(js|jsx)$/
}),
new OptimizeCSSAssetsPlugin({})
]
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader"
}
]
},
{
test: /\.css$/,
use: [
miniCSSExtractPlugin.loader,
{
loader: "css-loader"
}
]
},
{
test: /\.(png|jpg|gif|ico)$/,
use: [
{
loader: "file-loader?name=images/[hash].[ext]",
options: {
name: "assets/images/[hash].[ext]"
}
}
]
},
{
test: /\.(ttf|woff2?|eo(f|t)|svg)$/,
use: [
{
loader: "file-loader",
options: {
name: "assets/fonts/[hash].[ext]"
}
}
]
},
{
test: /\.(json)$/,
type: "javascript/auto",
use: [
{
loader: "file-loader",
options: {
name: "[folder]/[name].[ext]",
outputPath: "assets/locales/"
}
}
]
}
]
},
plugins: [
new htmlWebpackPlugin({
template: path.join(__dirname, "..", "public", "index.html")
}),
new miniCSSExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new cleanWebpackPlugin("../dist/*", {
root: __dirname + "../",
allowExternal: true
})
]
};
module.exports = config;
i18n/index.js
const i18n = require("i18next");
const initReactI18next = require("react-i18next").initReactI18next;
const langDetector = require("i18next-browser-languagedetector");
const backend = require("i18next-xhr-backend");
const moment = require("moment");
const resources = require("../../static/locales");
/*
Other codes...
*/
i18n.use(langDetector).use(initReactI18next);
var options;
switch (process.env.NODE_ENV) {
case "test":
options = {
whitelist: ["en", "pt"],
fallbackLng: "en",
resources,
ns: "translation",
defaultNS: "translation",
interpolation: {
format: function(value, format, lng) {
if (value instanceof Date) return moment(value).format(format);
return value.toString();
}
}
};
break;
case "production":
i18n.use(backend);
options = {
whitelist: ["en-US", "pt-BR"],
fallbackLng: {
pt: ["pt-BR"],
en: ["en-US"],
default: ["en"]
},
ns: ["button", "common", "lng", "info"],
defaultNS: "common",
backend: {
loadPath: "./assets/locales/{{lng}}/{{ns}}.json"
},
detection: {
order: ["querystring", "cookie", "navigator", "localStorage"]
},
lookupQuerystring: "lng",
caches: ["localStorage", "cookie"],
react: {
wait: true
},
interpolation: {
format: function(value, format, lng) {
if (format === "uppercase") return value.toUpperCase();
if (value instanceof Date) return moment(value).format(format);
return value;
}
}
};
break;
case "development":
i18n.use(backend);
options = {
whitelist: ["en-US", "pt-BR"],
fallbackLng: {
pt: ["pt-BR"],
en: ["en-US"],
default: ["en"]
},
ns: ["button", "common", "lng", "info"],
defaultNS: "common",
backend: {
loadPath: "./src/static/locales/{{lng}}/{{ns}}.json"
},
detection: {
order: ["querystring", "cookie", "navigator", "localStorage"]
},
lookupQuerystring: "lng",
caches: ["localStorage", "cookie"],
react: {
wait: true
},
interpolation: {
format: function(value, format, lng) {
if (format === "uppercase") return value.toUpperCase();
if (value instanceof Date) return moment(value).format(format);
return value;
}
}
};
break;
}
i18n.init(options);
module.exports = i18n;

Import component css chunk client side with react-loadable

How CSS files will load dynamically using react-loadable library on client side?
I have included react-loadable library on both server and client side rendering, from server-side rendering everything works fine but client side, how CSS will load dynamically?
webpack.config.prod.js : Client/Server -
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractCssChunks = require('extract-css-chunks-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
const { ReactLoadablePlugin } = require('react-loadable/webpack');
const publicPath = paths.servedPath;
const shouldUseRelativeAssetPaths = publicPath === './';
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
const publicUrl = publicPath.slice(0, -1);
const env = getClientEnvironment(publicUrl);
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
throw new Error('Production builds must have NODE_ENV=production.');
}
const cssFilename = 'static/css/[name].[contenthash:8].css';
const client = {
bail: true,
devtool: shouldUseSourceMap ? 'source-map' : false,
entry: [require.resolve('./polyfills'), paths.appIndexJs],
output: {
// The build folder.
path: paths.appBuild,
filename: 'static/js/[name].[chunkhash:8].js',
chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
publicPath,
devtoolModuleFilenameTemplate: info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)),
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
'react-native': 'react-native-web',
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
compact: true,
plugins: ['react-loadable/babel'],
},
},
{
test: /\.(?:css|less)$/,
use: ExtractCssChunks.extract({
use: [
{
loader: 'css-loader?modules',
options: {
minimize: true,
sourceMap: shouldUseSourceMap,
importLoaders: true,
localIdentName: '[name]__[local]__[hash:base64:7]',
},
},
{
loader: 'less-loader',
options: {
minimize: true,
sourceMap: shouldUseSourceMap,
importLoaders: true,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9',
],
flexbox: 'no-2009',
}),
],
},
},
],
fallback: 'style-loader',
}),
exclude: /\.(eot|woff|woff2|ttf|otf|svg)(\?[\s\S]+)?$/,
},
{
loader: require.resolve('file-loader'),
exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: false,
minifyCSS: true,
minifyURLs: true,
},
}),
new webpack.DefinePlugin(env.stringified),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
comparisons: false,
},
mangle: {
safari10: true,
},
output: {
comments: false,
ascii_only: true,
},
sourceMap: shouldUseSourceMap,
}),
new ExtractCssChunks({
filename: cssFilename,
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest.js',
minChunks: Infinity,
}),
new ManifestPlugin({
fileName: 'asset-manifest.json',
}),
new ReactLoadablePlugin({
filename: './build/react-loadable.json',
}),
new SWPrecacheWebpackPlugin({
dontCacheBustUrlsMatching: /\.\w{8}\./,
filename: 'service-worker.js',
logger(message) {
if (message.indexOf('Total precache size is') === 0) {
return;
}
if (message.indexOf('Skipping static resource') === 0) {
return;
}
console.log(message);
},
minify: true,
navigateFallback: `${publicUrl}/index.html`,
navigateFallbackWhitelist: [/^(?!\/__).*/],
staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
};
// Server render
const nodeExternals = require('webpack-node-externals');
const server = Object.assign({}, client);
server.target = 'node';
server.node = {
__filename: true,
__dirname: true,
};
server.externals = [nodeExternals()];
server.entry = [
'./server/middleware/renderer.js',
];
delete server.devtool;
delete server.node;
server.module = {};
server.plugins = [
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1,
}),
];
server.output = {
path: paths.appBuild,
filename: 'handleRender.js',
publicPath,
libraryTarget: 'commonjs2',
};
server.module.rules = [{
test: /\.(?:js|jsx)$/,
exclude: /node_modules/,
loader: require.resolve('babel-loader'),
options: {
compact: true,
plugins: ['react-loadable/babel'],
},
},
{
test: /\.(?:css|less)$/,
loader: 'css-loader/locals?modules&localIdentName=[name]__[local]__[hash:base64:7]!less-loader',
exclude: /\.(eot|woff|woff2|ttf|otf|svg)(\?[\s\S]+)?$/,
}];
module.exports = [server, client];
Server index.js:
...
import Loadable from 'react-loadable';
import serverRenderer from '../build/handleRender.js';
...
router.use('*', serverRenderer);
...
app.use(router);
// Pre-load all compoenents
Loadable.preloadAll().then(() => {
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log(`listening on ${PORT}...`);
});
}).catch((e) => {
console.log('Loadable Error : ', e);
});
renderer.js:
import { renderToStringWithData } from 'react-apollo';
import Loadable from 'react-loadable';
import { getBundles } from 'react-loadable/webpack';
...
const mainApp = renderToStringWithData(<Loadable.Capture
report={moduleName => modules.push(moduleName)}
>
<App req={req} context={context} client={client} />
</Loadable.Capture>);
...
const bundles = getBundles(JSON.parse(stats), modules);
const styles = bundles.filter(bundle => bundle.file.endsWith('.css'));
const scripts = bundles.filter(bundle => bundle.file.endsWith('.js'));
...
//mainApp=>html
const replacedStyle = html.replace(
'<link id="codeSplittingStyle">',
styles.map(bundle => `<link
rel="stylesheet"
href="/${bundle.file}"/>`).join('\n'),
);
const replacedScript = replacedStyle.replace(
'<script id="codeSplittingScript"></script>',
scripts.map(bundle => `<script
type="text/javascript"
src="/${bundle.file}"></script>`).join('\n'),
);
...
return res.send(replacedScript);
Browser.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Loadable from 'react-loadable';
import Browser from './layout/browser';
import registerServiceWorker from './registerServiceWorker';
Loadable.preloadReady().then(() => {
ReactDOM.hydrate(<Browser />, document.getElementById('root'));
});
registerServiceWorker();
Please have a look at "Desired output" section in extract-css-chunks-webpack-plugin repo (https://github.com/faceyspacey/extract-css-chunks-webpack-plugin#desired-output). It states that:
webpack-flush-chunks will scoop up the exact stylesheets to embed in your response. It essentially automates producing the above.
So you need to use webpack-flush-chunks in order to generate cssHash which is essential part of dynamic css loading as it determines when css chunks should be loaded.

how to solve this error You may need an appropriate loader to handle this file type

I got this error with this library https://github.com/react-native-web-community/react-native-web-linear-gradient/
the error link
https://github.com/react-native-web-community/react-native-web-linear-gradient/issues/1
details of error:
Module parse failed: Unexpected token (5:22)
You may need an appropriate loader to handle this file type.
my webpack:
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
const publicPath = '/';
const publicUrl = '';
const env = getClientEnvironment(publicUrl);
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
paths.appIndexJs,
],
output: {
pathinfo: true,
filename: 'static/js/bundle.js',
chunkFilename: 'static/js/[name].chunk.js',
publicPath: publicPath,
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
},
resolve: {
modules: ['node_modules', paths.appNodeModules].concat(
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
alias: {
'babel-runtime': path.dirname(
require.resolve('babel-runtime/package.json')
),
'react-native': 'react-native-web',
'react-native-linear-gradient': 'react-native-web-linear-gradient'
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson]),
],
},
module: {
strictExportPresence: true,
rules: [
{
test: /\.(js|jsx|mjs)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
eslintPath: require.resolve('eslint'),
baseConfig: {
extends: [require.resolve('eslint-config-react-app')],
},
ignore: false,
useEslintrc: false,
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
{
oneOf: [
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve('url-loader'),
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
},
},
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
presets: [require.resolve('babel-preset-react-app')],
cacheDirectory: true,
},
},
{
test: /\.css$/,
use: [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve('postcss-loader'),
options: {
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
autoprefixer({
browsers: [
'>1%',
'last 4 versions',
'Firefox ESR',
'not ie < 9', // React doesn't support IE8 anyway
],
flexbox: 'no-2009',
}),
],
},
},
],
},
{
exclude: [/\.js$/, /\.html$/, /\.json$/],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
],
},
],
},
plugins: [
new InterpolateHtmlPlugin(env.raw),
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml,
}),
new webpack.NamedModulesPlugin(),
new webpack.DefinePlugin(env.stringified),
new webpack.HotModuleReplacementPlugin(),
new CaseSensitivePathsPlugin(),
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
node: {
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
performance: {
hints: false,
},
};
the class who make the problem:
import React, { PureComponent } from 'react';
import { View } from 'react-native';
export default class LinearGradient extends PureComponent {
static defaultProps = {
start: {
x: 0.5,
y: 0,
},
end: {
x: 0.5,
y: 1,
},
locations: [],
colors: [],
};
state = {
width: 1,
height: 1,
};
measure = ({ nativeEvent }) =>
this.setState({
width: nativeEvent.layout.width,
height: nativeEvent.layout.height,
});
getAngle = () => {
// Math.atan2 handles Infinity
const angle =
Math.atan2(
this.state.width * (this.props.end.y - this.props.start.y),
this.state.height * (this.props.end.x - this.props.start.x)
) +
Math.PI / 2;
return angle + 'rad';
};
getColors = () =>
this.props.colors
.map((color, index) => {
const location = this.props.locations[index];
let locationStyle = '';
if (location) {
locationStyle = ' ' + location * 100 + '%';
}
return color + locationStyle;
})
.join(',');
render() {
return (
<View
style={[
this.props.style,
{ backgroundImage: `linear-gradient(${this.getAngle()},${this.getColors()})` },
]}
onLayout={this.measure}
>
{this.props.children}
</View>
);
}
}
static defaultProps and ()=> make the bug so what could be wrong?
Partial fix >>
Steps:
1-npm install babel babel-cli --save-dev on the library
2-I add "transpile": "babel src/index.js --out-file src/index-transpiled.js"
in package.json scripts
3-yarn transpile
4-I moved the ES5 file to my code and it worked
Update - Full Fix
I included my src folder and the libraries to babel too
// Process JS with Babel.
{
test: /\.(js|jsx|mjs)$/,
include: [
/src\/*/,
/node_modules\/react-native-/,
],
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
presets: [require.resolve('babel-preset-react-native')],
cacheDirectory: true
}
},
I think this is because of ES7 feature. Do you have stage-0 installed & added to your .babelrc or webpack.config.js file?
Here how you can do it:
npm i --save-dev babel-preset-stage-0
And then you should include it into webpack.config.js file like below:
loader: "babel-loader", // or just "babel"
query: {
presets: [ <other presets>, 'stage-0']
}
Or add it to .babelrc file:
{
"presets": ["stage-0"]
}
UPDATE
As I said earlier the issue belongs to ES7 feature. Seems like webpack can not resolve static keyword within react-native-web-linear-gradient module. So what I did to fix this issue:
I copied the source code from react-native-web-linear-gradient into my own component called LinearGradient. I didn't change anything within it.
I installed stage-0 and added it to .babelrc as i described above.
Later instead of using react-native-web-linear-gradient i use my LinearGradient component.
As a result i got gradient on my page. git project link.
Hope it will help!
This is how webpack can be configured to load assets, such as images (pngs, svgs, jpgs and so on):
npm install --save-dev file-loader
Add this in the webpack.config.js, under the module.exports.rules:
{
test: /\.(png|svg|jpg|gif)$/,
use: ["file-loader"]
}
Now, when you import MyImage from './my-image.png', that image will be processed and added to your output directory and the MyImage variable will contain the final url of that image after processing.

HMR not working with `withStyle`

Using Material-UI's withStyle,
with the example bellow, when changing the color to blue, I see on the console that HMR is doing its job updating modules but the changes don't actually appear on screen, I have to reload the page.
If I add a style property to the div and set the color to blue there, it appears properly on screen.
const styles = () => ({
root: {
color: 'black',
},
});
class Test extends React.Component {
render() {
const { classes } = this.props;
return (
<div calssName={classes.root}>
This is a test
</div>
)
}
}
const select = function (state) {
return state;
};
export default compose(
withStyles(styles),
connect(select),
)(Test);
I think I didn't totally understand this withStyles thing, my guess is a misconfiguration so here's my webpack.config.dev.js :
const Path = require('path');
const Webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
devtool: '#eval-source-map',
entry: [
'babel-polyfill',
Path.join(__dirname, '../../app/application/delegate'),
],
output: {
filename: 'bundle.js',
path: Path.join(__dirname, '../public/'),
publicPath: '/',
},
module: {
loaders: [
{
test: /\.jsx$|\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react', 'stage-2'],
plugins: [['react-transform', {
transforms: [{
imports: ['react'],
locals: ['module'],
transform: 'react-transform-hmr',
}],
}]],
},
},
{
test: /\.css$/,
use: ['css-hot-loader'].concat(ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader',
})),
},
{
test: /\.json$/,
loader: 'json',
},
],
},
plugins: [
new Webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
PLATFORM_ENV: JSON.stringify('web'),
},
}),
new Webpack.NoEmitOnErrorsPlugin(),
new ExtractTextPlugin('styles.css'),
],
resolve: {
extensions: ['.js', '.jsx', '.json'],
},
};

Resources