I have a React application configured with Django Application. I have different webpack config files for development and production, When I run "npm run start", it gives me error that:
Cannot read property 'tap' of undefined
package.json file:
{
"name": "project",
"version": "0.1.0",
"private": true,
"dependencies": {
"#babel/core": "7.1.0",
"#svgr/webpack": "2.4.1",
"ajv": "^6.5.4",
"ajv-keywords": "^3.2.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "9.0.0",
"babel-jest": "23.6.0",
"babel-loader": "8.0.4",
"babel-plugin-named-asset-import": "^0.2.2",
"babel-preset-react-app": "^5.0.4",
"bfj": "6.1.1",
"case-sensitive-paths-webpack-plugin": "2.1.2",
"chalk": "2.4.1",
"css-loader": "1.0.0",
"dotenv": "6.0.0",
"dotenv-expand": "4.2.0",
"eslint": "5.6.0",
"eslint-config-react-app": "^3.0.4",
"eslint-loader": "2.1.1",
"eslint-plugin-flowtype": "2.50.1",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-react": "7.11.1",
"file-loader": "2.0.0",
"fs-extra": "7.0.0",
"identity-obj-proxy": "3.0.0",
"jest": "23.6.0",
"jest-pnp-resolver": "1.0.1",
"jest-resolve": "23.6.0",
"mini-css-extract-plugin": "0.4.3",
"optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.1.0",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.0.6",
"postcss-safe-parser": "4.0.1",
"react": "^16.6.0",
"react-app-polyfill": "^0.1.3",
"react-dev-utils": "^6.0.5",
"react-dom": "^16.6.0",
"resolve": "1.8.1",
"sass-loader": "7.1.0",
"style-loader": "0.23.0",
"terser-webpack-plugin": "1.1.0",
"url-loader": "1.1.1",
"webpack": "4.19.1",
"webpack-dev-server": "3.1.9",
"webpack-manifest-plugin": "2.0.4",
"workbox-webpack-plugin": "3.6.2"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"resolver": "jest-pnp-resolver",
"setupFiles": [
"react-app-polyfill/jsdom"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx}"
],
"testEnvironment": "jsdom",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"json",
"web.jsx",
"jsx",
"node"
]
},
"babel": {
"presets": [
"react-app"
]
},
"devDependencies": {
"html-webpack-plugin": "^4.0.0-beta.2",
"react-hot-loader": "^4.0.0",
"tap": "^11.0.0-rc.3",
"webpack-bundle-tracker": "^0.4.2-beta",
"webpack-cli": "^3.1.2"
}
}
webpack.config.dev.js file:
"use strict";
const path = require("path");
const webpack = require("webpack");
const PnpWebpackPlugin = require("pnp-webpack-plugin");
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 getCSSModuleLocalIdent = require("react-dev-
utils/getCSSModuleLocalIdent");
const getClientEnvironment = require("./env");
const paths = require("./paths");
const ManifestPlugin = require("webpack-manifest-plugin");
const ModuleNotFoundPlugin = require("react-dev-
utils/ModuleNotFoundPlugin");
// Webpack uses `publicPath` to determine where the app is being
served from.
// In development, we always serve from the root. This makes config
easier.
//const publicPath = '/';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in
JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than
%PUBLIC_PATH%xyz.
const publicPath = "http://localhost:3000/";
const publicUrl = "http://localhost:3000/";
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
const BundleTracker = require("webpack-bundle-tracker");
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: cssOptions
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve("postcss-loader"),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: "postcss",
plugins: () => [
require("postcss-flexbugs-fixes"),
require("postcss-preset-env")({
autoprefixer: {
flexbox: "no-2009"
},
stage: 3
})
]
}
}
];
if (preProcessor) {
loaders.push(require.resolve(preProcessor));
}
return loaders;
};
// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate
file.
module.exports = {
mode: "development",
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebook/create-react-app/issues/343
devtool: "cheap-module-source-map",
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
require.resolve("react-dev-utils/webpackHotDevClient"),
require.resolve("webpack-dev-server/client") + "?
http://localhost:3000",
require.resolve("webpack/hot/dev-server"),
// Finally, this is your app's code:
paths.appIndexJs
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
],
output: {
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// This does not produce a real file. It's just the virtual path that is
// served by WebpackDevServer in development. This is the JS bundle
// containing code from all our entry points, and the Webpack runtime.
filename: "static/js/bundle.js",
// There are also additional JS chunk files if you use code splitting.
chunkFilename: "static/js/[name].chunk.js",
// This is the URL that app is served from. We use "/" in development.
publicPath: publicPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/")
},
optimization: {
// Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
splitChunks: {
chunks: "all",
name: false
},
minimize: false,
// Keep the runtime chunk seperated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
runtimeChunk: true
},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253
modules: ["node_modules"].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebook/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: [".mjs", ".web.js", ".js", ".json", ".web.jsx", ".jsx"],
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
"react-native": "react-native-web"
},
plugins: [
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
// guards against forgotten dependencies and such.
PnpWebpackPlugin,
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new BundleTracker({
path: paths.statsRoot,
filename: "webpack-stats.dev.json"
}),
new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson])
]
},
resolveLoader: {
plugins: [
// Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
// from the current package.
PnpWebpackPlugin.moduleLoader(module)
]
},
module: {
strictExportPresence: true,
rules: [
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.(js|mjs|jsx)$/,
enforce: "pre",
use: [
{
options: {
formatter: require.resolve("react-dev-utils/eslintFormatter"),
eslintPath: require.resolve("eslint")
},
loader: require.resolve("eslint-loader")
}
],
include: paths.appSrc
},
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "static/media/[name].[hash:8].[ext]"
}
},
// Process application JS with Babel.
// The preset includes JSX, Flow, and some ESnext features.
{
test: /\.(js|mjs|jsx)$/,
include: paths.appSrc,
loader: require.resolve("babel-loader"),
options: {
customize: require.resolve(
"babel-preset-react-app/webpack-overrides"
),
plugins: [
[
require.resolve("babel-plugin-named-asset-import"),
{
loaderMap: {
svg: {
ReactComponent: "#svgr/webpack?-prettier,-svgo![path]"
}
}
}
]
],
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
// Don't waste time on Gzipping the cache
cacheCompression: false
}
},
// Process any JS outside of the app with Babel.
// Unlike the application JS, we only compile the standard ES features.
{
test: /\.(js|mjs)$/,
exclude: /#babel(?:\/|\\{1,2})runtime/,
loader: require.resolve("babel-loader"),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve("babel-preset-react-app/dependencies"),
{ helpers: true }
]
],
cacheDirectory: true,
// Don't waste time on Gzipping the cache
cacheCompression: false,
// If an error happens in a package, it's possible to be
// because it was compiled. Thus, we don't want the browser
// debugger to show the original code. Instead, the code
// being evaluated would be much more helpful.
sourceMaps: false
}
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
// By default we support CSS Modules with the extension .module.css
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1
})
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
modules: true,
getLocalIdent: getCSSModuleLocalIdent
})
},
// Opt-in support for SASS (using .scss or .sass extensions).
// Chains the sass-loader with the css-loader and the style-loader
// to immediately apply all styles to the DOM.
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders({ importLoaders: 2 }, "sass-loader")
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 2,
modules: true,
getLocalIdent: getCSSModuleLocalIdent
},
"sass-loader"
)
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/\.(js|mjs|jsx)$/, /\.html$/, /\.json$/],
loader: require.resolve("file-loader"),
options: {
name: "static/media/[name].[hash:8].[ext]"
}
}
]
}
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
]
},
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin({
inject: true,
template: paths.appHtml
}),
// new InterpolateHtmlPlugin({
// name: "xu"
// }),
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
// In development, this will be an empty string.
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
// This gives some necessary context to module not found errors, such as
// the requesting resource.
new ModuleNotFoundPlugin(paths.appPath),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
// This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebook/create-react-app/issues/240
new CaseSensitivePathsPlugin(),
// If you require a missing module and then `npm install` it, you still have
// to restart the development server for Webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebook/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
// Generate a manifest file which contains a mapping of all asset filenames
// to their corresponding output file so that tools can pick it up without
// having to parse `index.html`.
new ManifestPlugin({
fileName: "asset-manifest.json",
publicPath: publicPath
})
],
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
node: {
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty"
},
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false
};
start.js file:
"use strict";
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = "development";
process.env.NODE_ENV = "development";
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on("unhandledRejection", err => {
throw err;
});
// Ensure environment variables are read.
require("../config/env");
const fs = require("fs");
const chalk = require("chalk");
const webpack = require("webpack");
const WebpackDevServer = require("webpack-dev-server");
const clearConsole = require("react-dev-utils/clearConsole");
const checkRequiredFiles = require("react-dev-utils/checkRequiredFiles");
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls
} = require("react-dev-utils/WebpackDevServerUtils");
const openBrowser = require("react-dev-utils/openBrowser");
const paths = require("../config/paths");
const config = require("../config/webpack.config.dev");
const createDevServerConfig =
require("../config/webpackDevServer.config");
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || "0.0.0.0";
if (process.env.HOST) {
console.log(
chalk.cyan(
` Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(
`Learn more here:`
);
console.log();
}
// We require that you explictly set browsers and do not fall
back to
// browserslist defaults.
const { checkBrowsers } = require("react-dev-utils/browsersHelper");
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === "true" ? "https" : "http";
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
// Serve webpack assets generated by the compiler over a web server.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const devServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
devServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan("Starting the development server...\n"));
openBrowser(urls.localUrlForBrowser);
});
["SIGINT", "SIGTERM"].forEach(function(sig) {
process.on(sig, function() {
devServer.close();
process.exit();
});
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
Error Stacktrace:
> project#0.1.0 start /usr/react_projects/project
> node scripts/start.js
Cannot read property 'tap' of undefined
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! project#0.1.0 start: `node scripts/start.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the project#0.1.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
I don't understand why it is giving Cannot find property "tap" undefined.
I had the same exact problem. You have to add #babel/preset-react library to your package.json file.
Run yarn yarn add #babel/preset-react or npm install #babel/preset-react
Related
I have a Symfony project, where the frontend-pipeline is built with Webpack Encore, I would like to add React to the project and have a React widget inserted into one of my server-side rendered pages.
I've followed the documentation and extended my webpack.config.js with the following one-liner .enableReactPreset(). I'm also writting my JS in TypeScript (I already have some non-react based JS in the project that's compiled from TS, thus I'm writing my react components in .tsx files).
I create an entrypoint for my react widget that looks like this
import React from "react";
import ReactDOM from "react-dom";
import "./map.scss";
import App from "./components/App";
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("map-app")
);
When I start the app in watch mode with encore dev I don't see any errors in my console and the code compiles, but when I check the output in my browser I get an error, telling me that it can not read property render of undefined.
I've logged out React and ReactDOM and they both show to be undefined.
The strange thing is that my editor (PHPStrom) sees the imported module pointing to the respective index.d.ts files of these packages and intellisense works on them (I get the render method autocompleted for instance).
I've enabled "allowSyntheticDefaultImports": true in my project's tsconfig.json.
Now I could solve the problem with a workaround. If I import these libraries like so:
import * as React from "react";
import * as ReactDOM from "react-dom";
console.log(React); // no longer undefined, I get an object with all of react's methods
It works, but it's a bit awkward, and also this way I can't import the named components from react.
For instance this also fails:
import {useState} from "react";
console.log(useState); // undefined
I can only make it work like so:
import * as React from "react";
console.log(React.useState); // I get the function
I would like to understand why is this happening and how to make the default exports work properly like in all other React projects.
My package.json currently looks like this:
{
"devDependencies": {
"#babel/preset-react": "^7.16.7",
"#symfony/webpack-encore": "^1.7.*",
"#types/jquery": "^3.3.33",
"#types/leaflet": "^1.5.5",
"#types/leaflet.markercluster": "^1.4.2",
"#types/react": "^17.0.38",
"#types/react-dom": "^17.0.11",
"#types/react-router-dom": "^5.3.2",
"autoprefixer": "^9.6.1",
"core-js": "^3.0.0",
"file-loader": "^6.2.0",
"fork-ts-checker-webpack-plugin": "^5.0.0",
"postcss": "^8.4.5",
"postcss-loader": "^6.0.0",
"sass": "^1.3.0",
"sass-loader": "^12.0.0",
"ts-loader": "^9.0.0",
"typescript": "^3.6.4",
"webpack-notifier": "^1.6.0"
},
"repository": {
"type": "git",
"url": "https://github.com/Cooty/the-bedechka-case"
},
"name": "the-bedechka-case-website-frontend",
"license": "MIT",
"private": true,
"scripts": {
"dev-server": "encore dev-server",
"dev": "encore dev",
"watch": "encore dev --watch",
"build": "encore production --progress"
},
"browserslist": [
"defaults"
],
"dependencies": {
"bootstrap": "^4.4.1",
"fg-loadcss": "^2.1.0",
"html5sortable": "^0.10.0",
"jquery": "3.5",
"leaflet": "^1.7.1",
"leaflet.markercluster": "^1.4.1",
"popper.js": "^1.16.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-leaflet": "^3.2.2",
"react-router-dom": "^6.2.1"
}
}
This is my current tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"jsx": "react",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"noEmitOnError": true,
"moduleResolution": "node",
"allowSyntheticDefaultImports": true
},
"exclude": [
"vendor",
"var",
"translations",
"tests",
"src",
"public",
"node_modules"
]
}
and my webpack.config.js
const Encore = require("#symfony/webpack-encore");
const babelLoader = {
test: /\.js$/,
loader: "babel-loader",
options: {
presets: [
[
"#babel/preset-env",
{
"useBuiltIns": "entry",
"corejs": {version: 3, proposals: true}
},
]
]
}
};
Encore
.setOutputPath("public/build/")
.copyFiles({
from: "./assets/images",
to: "images/[path][name].[hash:8].[ext]"
})
.setPublicPath("/build")
.cleanupOutputBeforeBuild()
.enableVersioning(Encore.isProduction())
.enableSourceMaps()
.enableReactPreset()
.addEntry("app", "./templates/ts/app.ts")
.addEntry("home", "./templates/home/home.ts")
.addEntry("map", "./templates/map/map.tsx")
.addEntry("yt", "./templates/components/youtube-embed/youtube-embed.ts")
.addEntry("admin", "./templates/admin/ts/admin.ts")
.addStyleEntry("the-crew", "./templates/the-crew/the-crew.scss")
.addStyleEntry("protagonists", "./templates/protagonists/protagonists.scss")
.addStyleEntry("screenings", "./templates/screenings/screenings.scss")
.addStyleEntry("partners", "./templates/partners/partners.scss")
.addStyleEntry("critical-path", "./templates/scss/critical-path.scss")
.addStyleEntry("critical-path-home", "./templates/home/critical-path-home.scss")
.addStyleEntry("critical-path-subpages", "./templates/scss/critical-path-subpages.scss")
.enableTypeScriptLoader()
.enableForkedTypeScriptTypesChecking()
.addLoader(babelLoader)
.enablePostCssLoader()
.enableSassLoader()
.enableSingleRuntimeChunk()
.splitEntryChunks();
const config = Encore.getWebpackConfig();
config.optimization.noEmitOnErrors = true;
module.exports = config;
You can also checkout the branch where this feature is being implemented here.
In our case we have in compiler options "esModuleInterop": true, so we have something like this:
{
"ecmaVersion": 2021,
"sourceType": "module",
"compilerOptions": {
"noImplicitAny": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"jsx": "react"
},
"include": [
"assets/js/**/*.ts",
"assets/js/**/*.tsx",
"assets/js/**/*.js",
"assets/js/**/*.jsx",
"templates/**/*.ts",
"templates/**/*.tsx",
"templates/**/*.js",
"templates/**/*.jsx"
],
"exclude": [
"node_modules",
"public",
"vendor"
]
}
We have a more complex webpackconfig be we use the same options regarding React:
const Encore = require('#symfony/webpack-encore');
const path = require('path');
const ESLintPlugin = require('eslint-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const {
bundlesScssPath,
bundlesJsPath,
templatesPath
} = require('./webpack/configs/utils.config');
const vendorsAddEntries = require('./webpack/configs/vendors-add-entries.config');
const projectAddEntries = require('./webpack/configs/project-add-entries.config');
const coreVendorsAddEntries = require('./webpack/configs/core-vendors-add-entries.config');
const designStoryAddEntries = require('./webpack/configs/design-story-add-entries.config');
const cssAddEntries = require('./webpack/configs/css-add-entries.config');
vendorsAddEntries();
coreVendorsAddEntries();
projectAddEntries();
designStoryAddEntries();
cssAddEntries();
// +-------------+
// | Main config |
// +-------------+
// Manually configure the runtime environment if not already configured yet by the "encore" command.
// It's useful when you use tools that rely on webpack.config.js file.
Encore
// directory where compiled assets will be stored
.setOutputPath('public/build/')
// public path used by the web server to access the output path
.setPublicPath('/build')
// only needed for CDN's or sub-directory deploy
//.setManifestKeyPrefix('build/')
/*
* ENTRY CONFIG
*
* Add 1 entry for each "page" of your app
* (including one that's included on every page - e.g. "app")
*
* Each entry will result in one JavaScript file (e.g. app.js)
* and one CSS file (e.g. app.scss) if you JavaScript imports CSS.
*/
// +-------------------+
// | common js entries |
// +-------------------+
// .addEntry('app', './assets/js/app.ts')
.addEntry('vendors', path.resolve('./' + path.join(bundlesJsPath, 'vendors/index.ts')))
.addEntry('components', path.resolve('./' + path.join(templatesPath, 'DesignStory/components/components.ts')))
// +---------------+
// | configuration |
// +---------------+
/*
* FEATURE CONFIG
*
* Enable & configure other features below. For a full
* list of features, see:
* https://symfony.com/doc/current/frontend.html#adding-more-features
*/
.cleanupOutputBeforeBuild()
.enableBuildNotifications()
.enableSourceMaps(!Encore.isProduction())
// enables hashed filenames (e.g. app.abc123.css) and assets cache issues on production
.enableVersioning(Encore.isProduction())
// When enabled, Webpack "splits" your files into smaller pieces for greater optimization.
.splitEntryChunks()
// will require an extra script tag for runtime.js
// but, you probably want this, unless you're building a single-page app
.enableSingleRuntimeChunk()
// enables #babel/preset-env polyfills
.configureBabel(() => {}, {
useBuiltIns: 'usage',
corejs: 3
})
// +------------+
// | TS + React |
// +------------+
// uncomment if you use API Platform Admin (composer req api-admin)
.enableReactPreset()
.enableTypeScriptLoader((tsConfig) => {
// You can use this callback function to adjust ts-loader settings
// https://github.com/TypeStrong/ts-loader/blob/master/README.md#loader-options
// For example:
// tsConfig.silent = false
})
// optionally enable forked type script for faster builds
// https://www.npmjs.com/package/fork-ts-checker-webpack-plugin
// requires that you have a tsconfig.json file that is setup correctly.
.enableForkedTypeScriptTypesChecking(options => {
delete options.parser;
})
.addPlugin(new ESLintPlugin({
extensions: ['js', 'jsx', 'ts', 'tsx'],
exclude: [
'node_modules',
'vendor'
],
}))
.addPlugin(new StyleLintPlugin({
context: path.resolve(__dirname),
configFile: '.stylelintrc.json',
files: [
path.join(bundlesScssPath, '**/*.s+(a|c)ss'),
path.join(templatesPath, '**/*.s+(a|c)ss')
]
}))
// +-----------------+
// | SASS/postprefix |
// +-----------------+
// enables Sass/SCSS support
.enableSassLoader((options) => {
// add or set custom options
// options.includePaths: ["absolute/path/a", "absolute/path/b"];
// options.warnRuleAsWarning = true;
}, {}
)
// Convert fonts to base64 inline (avoid font loading issue on pdf to html generation with wkhtml2pdf)
.addLoader({
test: /\.(ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
use: ['base64-inline-loader'],
type: 'javascript/auto',
})
// enable autoprefixing for css
.enablePostCssLoader((options) => {
options.postcssOptions = {
// the directory where the postcss.config.js file is stored
config: path.resolve(__dirname, 'postcss.config.js')
};
})
// uncomment to get integrity="..." attributes on your script & link tags
// requires WebpackEncoreBundle 1.4 or higher
//.enableIntegrityHashes()
.addExternals(
{
'bazinga-translator': 'Translator'
}
)
// uncomment if you're having problems with a jQuery plugin
.autoProvidejQuery()
// you can use this method to provide other common global variables,
// such as '_' for the 'underscore' library
// .autoProvideVariables({
// $: 'jquery',
// jQuery: 'jquery',
// 'window.jQuery': 'jquery',
// })
.copyFiles({
from: './assets/images',
to: 'images/[path][name].[ext]',
pattern: /\.(png|jpg|jpeg|svg|ico|gif)$/
})
// +-------------+
// | performance |
// +-------------+
// A simple technique to improve the performance of web applications is to reduce
// the number of HTTP requests inlining small files as base64 encoded URLs in the
// generated CSS files.
.configureImageRule({
// tell Webpack it should consider inlining
type: 'asset',
//maxSize: 4 * 1024, // 4 kb - the default is 8kb
})
// same here
.configureFontRule({
type: 'asset',
//maxSize: 4 * 1024
})
;
if (!Encore.isRuntimeEnvironmentConfigured()) {
Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}
module.exports = Encore.getWebpackConfig();
Hopes it will help
I'm writing a React component library which I want to use in other projects without much overhead ( bit, create-react-library, generact, etc. ) and without publishing. I want to use npm install ../shared_lib to add it to my project as a symlink in /node_modules. This command adds the symlink to project node_modules. In my shared_lib I just have a test to export default a <div></div>:
import React from 'react';
const TryTest = function() {
return (
<div>
TryTest
</div>
)
}
export default TryTest;
The problem I'm facing is the following error when I import the component into my working project:
import TryTest from 'shared_lib';
Error:
ERROR in ../shared_lib/src/index.js 6:4
Module parse failed: Unexpected token (6:4)
You may need an appropriate loader to handle this file type.
| const TryTest = function() {
| return (
> <div>
| TryTest
| </div>
# ./src/App.js 27:0-33 28:12-19
# ./src/index.js
# multi babel-polyfill ./src/index.js
If I import anything from shared_lib other than a file with jsx - for example, a string or a function, etc. - it works fine.
EDIT: the application webpack has resolve object's symlinks prop set to false:
resolve: {
symlinks: false
},
EDIT: After applying the solution in the answer below (https://stackoverflow.com/a/60980492/3006493), I later changed symlinks prop back to true. I didn't need to set it to false for the solution to work and render shared_lib components.
My app's loader:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ 'babel-loader' ]
}
EDIT: When I applied the solution in the answer below, the loader now looks like this:
{
test: /\.jsx?$/,
include: [
path.join( __dirname, 'src'), // app/src
fs.realpathSync(__dirname + '/node_modules/shared_lib'), // app/node_modules/shared_lib/dist/shared_lib.js
],
exclude: /node_modules/,
use: [ {
loader: 'babel-loader',
options: require("./package.json").babel
}
]
}
App's current .babelrc settings (I also tried removing .babelrc and including the presets in package.json with same result):
{
"presets": [ "#babel/preset-react", "#babel/preset-env"]
}
**EDIT: After applying the solution in the answer below, I ended up putting babel presets back into package.json.
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
},
I researched for a while to find a solution to this and apparently webpack has issues bundling symlinked react components? I am not using create-react-app.
So, I tried to bundle the shared_lib before importing it into the project, just to see what would happen. Here's the final webpack config (I tried other configurations as well):
const pkg = require('./package.json');
const path = require('path');
const buildPath = path.join( __dirname, 'dist' );
const clientPath = path.join( __dirname, 'src');
const depsPath = path.join( __dirname, 'node_modules');
const libraryName = pkg.name;
module.exports = [
'cheap-module-source-map'
].map( devtool => ({
bail: true,
mode: 'development',
entry: {
lib : [ 'babel-polyfill', path.join( clientPath, 'index.js' ) ]
},
output: {
path: buildPath,
filename: 'shared_lib.js',
libraryTarget: 'umd',
publicPath: '/dist/',
library: libraryName,
umdNamedDefine: true
},
// to avoid bundling react
externals: {
'react': {
commonjs: 'react',
commonjs2: 'react',
amd: 'React',
root: 'React'
}
},
module: {
rules: [
{
test: /\.jsx?$/,
include: [
clientPath
],
exclude: /node_modules/,
use: [ 'babel-loader' ],
},
]
},
devtool,
optimization: {
splitChunks: {
chunks: 'all',
},
}
}));
And the package.json for the shared_lib
{
"name": "shared_lib",
"version": "1.0.0",
"description": "",
"main": "dist/shared_lib.js",
"scripts": {
"clean": "rm -rf dist/",
"build": "$(npm bin)/webpack --config ./webpack.config.js",
"prepublish": "npm run clean && npm run build"
},
"author": "",
"license": "ISC",
"peerDependencies": {
"react": "^16.8.6"
},
"devDependencies": {
"react": "^16.8.6",
"#babel/core": "^7.9.0",
"#babel/preset-env": "^7.9.0",
"#babel/preset-react": "^7.9.4",
"babel-loader": "^8.1.0",
"babel-polyfill": "^6.26.0",
"webpack": "^4.42.1",
"webpack-cli": "^3.3.11"
},
"babel": {
"presets": [
"#babel/preset-react",
"#babel/preset-env"
]
}
}
The package is bundled without errors:
When I try to import the component in the same way:
import TryTest from 'shared_lib';
The console.log returns undefined.
The path to the library file in my app is fine, because if I erase everything in shared_lib/dist/shared_lib.js and just write export default 1 the console.log(TryTest) in my App.js will return 1.
I tried changing libraryTarget property in shared_lib/webpack.config to libraryTarget: 'commonjs'. The result of console.log(TryTest) becomes {shared_lib: undefined}.
Has anyone ever run into this?
I found what finally worked for me and rendered the symlinked shared_lib to the app.
This answer: https://github.com/webpack/webpack/issues/1643#issuecomment-552767686
Worked well rendering symlinked shared_lib components. I haven't discovered any drawbacks from using this solution, but it's the only one that worked so far.
I am not able to configure Webpack with react in development mode.
Here is my package JSON :
...
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.4",
"babel-preset-es2015": "^6.24.1",
"gulp": "^4.0.0",
"gulp-sass": "^4.0.1",
"webpack": "^4.12.2",
"webpack-stream": "^4.0.3"
}
...
I am getting this error in the browser :
Uncaught Error: Minified React error #37; visit http://facebook.github.io/react/docs/error-decoder.html?invariant=37 for the full message or use the non-minified dev environment
When I set web pack to mode development :
const DIR_PAGES = path.join(__dirname, 'pages');
const DIR_TARGET = path.join(__dirname, '..', 'assets');
const DIR_TARGET_PAGES = path.join(__dirname, '..', 'assets', 'pages');
module.exports = {
mode: "development",
/**
* DEFINE PAGES JS HERE
*/
entry: {
'test' : path.join(DIR_PAGES, 'test', 'test.js'),
},
resolve: {
extensions: ['.js', '.jsx']
},
/**
* HOW TO TRANSCODE JAVASCRIPT
*/
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
/**
* OUTPUT LOCATION
*/
output: {
path: DIR_TARGET_PAGES,
filename: '[name]/[name].js'
},
};
I am building using webpack-stream. here is my build task :
const webpack_stream = require('webpack-stream');
const webpack_config = require('./webpack.config.js');
gulp.task('webpack', function() {
return webpack_stream(webpack_config)
.pipe(gulp.dest(DIR_TARGET_JS));
});
I am getting this error while building web pack using gulp :
[13:57:12] 'webpack' errored after 161 ms
[13:57:12] WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
- configuration has an unknown property 'mode'. These properties are valid:
object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry, externals?, loader?, module?, name?, node?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, stats?, target?, watch?, watchOptions? }
For typos: please correct them.
For loader options: webpack 2 no longer allows custom properties in configuration.
Loaders should be updated to allow passing options via loader options in module.rules.
Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:
plugins: [
new webpack.LoaderOptionsPlugin({
// test: /\.xxx$/, // may apply this only for some modules
options: {
mode: ...
}
})
]
...
I don't know what to do can you help me please
Thank you
Does any one know what this Webpack error is caused by:
Module build failed: Unknown word (2:1)
var content = require("!!../../../../../../node_modules/css-loader/index.js?{\"importLoaders\":1}!./styles.css");
if(typeof content === 'string') content = [[module.id, content, '']];
This occurs when running two instances of webpack, one for the client and one for the server. The client compile fine, however the server prodcuces this error. If I run the config scripts separately there are no issues. I'm assuming there is some kind of conflict with the same CSS file being processed twice? I would like to be able to implement isomorphic-style-loader however even with this loader in replace of style-loader the error occurs. Any help would be greatly appreciated, hit a wall with this one.
start.js
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const { exec } = require('child_process');
const fs = require('fs');
const chalk = require('chalk');
const webpack = require('webpack');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const paths = require('../config/paths');
// const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
//if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
if (!checkRequiredFiles([paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_CLIENT_PORT = parseInt(process.env.PORT, 10) || 3000;
const DEFAULT_SERVER_PORT = parseInt(process.env.PORT, 10) || 5678;
const HOST = process.env.HOST || '0.0.0.0';
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `detect()` Promise resolves to the next free port.
choosePort(HOST, DEFAULT_CLIENT_PORT)
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
// We do this before importing the wepack.config.client.dev otherwise
// REACT_APP_CLIENT_PORT won't be set at new webpack.DefinePlugin(env.stringified)
process.env.REACT_APP_CLIENT_PORT = port
const configWebpackClient = require('../config/webpack.config.client.dev');
// Create a webpack compiler that is configured with custom messages.
// we use different compiler
//const compiler = createCompiler(webpack, configWebpackClient, appName, urls, useYarn);
const compiler = webpack(configWebpackClient);
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(proxySetting, paths.appPublic);
const createDevServerConfig = require('../config/webpackDevServer.config');
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
const clientServer = new WebpackDevServer(compiler, serverConfig);
// Launch WebpackDevServer.
clientServer.listen(port, HOST, err => {
if (err) {
return console.log(err);
}
if (isInteractive) {
clearConsole();
}
console.log(chalk.cyan(`Starting the client on port ${port}...\n`));
choosePort(HOST, DEFAULT_SERVER_PORT)
.then(portServer => {
if (portServer == null) {
// We have not found a port.
return;
}
process.env.REACT_APP_SERVER_PORT = portServer;
const configWebpackServer = require('../config/webpack.config.server');
const compiler = webpack(configWebpackServer);
const urls = prepareUrls(protocol, HOST, portServer);
let isServerRunning;
compiler.watch({ // watch options:
aggregateTimeout: 300,
}, function(err, stats) {
const messages = formatWebpackMessages(stats.toJson({}, true));
if (messages.errors.length) {
console.log(messages.errors.join('\n\n'));
}
if (err)
console.log('error on webpack server', err);
if (!isServerRunning) {
isServerRunning = true
const nodemon = exec('nodemon --watch build/server build/server/bundle.js build/server/bundle.js')
// This is to outpout in the terminal the child process
nodemon.stdout.on('data', function (data) {
console.log(data.toString());
});
nodemon.on('exit', function (code) {
console.log('nodemon process exited with code ' + code.toString());
});
console.log(chalk.yellow(`Starting the server on port ${portServer}...\n`));
// setTimeout(() => { openBrowser(urls.localUrlForBrowser, {app: 'firefoxdeveloperedition'}) }, 1000);
}
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
});
['SIGINT', 'SIGTERM'].forEach(function(sig) {
process.on(sig, function() {
clientServer.close();
process.exit();
})
});
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
webpack.config.base.js
'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 eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');
const PROD = process.env.NODE_ENV === 'production';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
module.exports = {
bail: PROD,
// You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
devtool: PROD ? 'source-map' : 'cheap-module-source-map',
entry: [],
output: {},
resolve: {
// This allows you to set a fallback for where Webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebookincubator/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
// It is guaranteed to exist because we tweak it in `env.js`
process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebookincubator/create-react-app/issues/290
extensions: ['.js', '.json', '.jsx'],
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
},
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc),
],
},
module: {
strictExportPresence: true,
rules: [
// TODO: Disable require.ensure as it's not a standard language feature.
// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
// { parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.(js|jsx)$/,
enforce: 'pre',
use: [
{
options: {
formatter: eslintFormatter,
},
loader: require.resolve('eslint-loader'),
},
],
include: paths.appSrc,
},
// ** ADDING/UPDATING LOADERS **
// The "file" loader handles all assets unless explicitly excluded.
// The `exclude` list *must* be updated with every change to loader extensions.
// When adding a new loader, you must add its `test`
// as a new entry in the `exclude` list for "file" loader.
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
{
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.css$/,
/\.json$/,
/\.bmp$/,
/\.gif$/,
/\.jpe?g$/,
/\.png$/,
],
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash:8].[ext]',
},
},
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
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)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
// ** STOP ** Are you adding a new loader?
// Remember to add the new extension(s) to the "file" loader exclusion list.
],
},
plugins: [
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how Webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
],
};
webpack.config.client.dev.js
'use strict';
const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const paths = require('./paths');
const getClientEnvironment = require('./env');
const WebpackNotifierPlugin = require('webpack-notifier');
const base = require('./webpack.config.base');
const config = Object.assign({}, base)
config.entry = [
// Include an alternative client for WebpackDevServer. A client's job is to
// connect to WebpackDevServer by a socket and get notified about changes.
// When you save a file, the client will either apply hot updates (in case
// of CSS changes), or refresh the page (in case of JS changes). When you
// make a syntax error, this client will display a syntax error overlay.
// Note: instead of the default WebpackDevServer client, we use a custom one
// to bring better experience for Create React App users. You can replace
// the line below with these two lines if you prefer the stock client:
// require.resolve('webpack-dev-server/client') + '?/',
// require.resolve('webpack/hot/dev-server'),
require.resolve('react-dev-utils/webpackHotDevClient'),
// We ship a few polyfills by default:
require.resolve('./polyfills'),
// Errors should be considered fatal in development
require.resolve('react-error-overlay'),
// Finally, this is your app's code:
paths.appIndexJs,
// We include the app code last so that if there is a runtime error during
// initialization, it doesn't blow up the WebpackDevServer client, and
// changing JS code would still trigger a refresh.
]
config.output = {
// Next line is not used in dev but WebpackDevServer crashes without it:
path: paths.appBuild,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: true,
// This does not produce a real file. It's just the virtual path that is
// served by WebpackDevServer in development. This is the JS bundle
// containing code from all our entry points, and the Webpack runtime.
filename: 'static/js/bundle.js',
// There are also additional JS chunk files if you use code splitting.
chunkFilename: 'static/js/[name].chunk.js',
// This is the URL that app is served from. We use "/" in development.
publicPath: '/',
hotUpdateChunkFilename: 'static/[id].[hash].hot-update.js',
hotUpdateMainFilename: 'static/[hash].hot-update.json',
// Point sourcemap entries to original disk location
devtoolModuleFilenameTemplate: info =>
path.resolve(info.absoluteResourcePath),
}
config.module.rules = config.module.rules.concat([
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
include: paths.appSrc,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", // translates CSS into CommonJS
options: {
importLoaders: 1
}
}
]
},
])
config.plugins = config.plugins.concat([
// This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(),
// If you require a missing module and then `npm install` it, you still have
// to restart the development server for Webpack to discover it. This plugin
// makes the discovery automatic so you don't have to restart.
// See https://github.com/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
new WebpackNotifierPlugin({
title: 'Webpack',
excludeWarnings: true,
alwaysNotify: true,
contentImage: path.join(__dirname, '../ahamo-logo.png')
}),
new webpack.LoaderOptionsPlugin({
debug: true
}),
])
// Turn off performance hints during development because we don't do any
// splitting or minification in interest of speed. These warnings become
// cumbersome.
config.performance = {
hints: false,
}
// Some libraries import Node modules but don't use them in the browser.
// Tell Webpack to provide empty mocks for them so importing them works.
config.node = {
fs: 'empty',
net: 'empty',
tls: 'empty',
},
module.exports = config
webpack.config.server.js
'use strict';
const path = require('path');
const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const paths = require('./paths');
const nodeExternals = require('webpack-node-externals');
const getClientEnvironment = require('./env');
const base = require('./webpack.config.base');
const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);
const config = Object.assign({}, base)
config.target = 'node'
config.entry = paths.serverIndexJs
config.externals = [nodeExternals()] // / in order to ignore all modules in node_modules folder
config.output = {
path: paths.serverBuild,
filename: 'bundle.js',
publicPath: '/'
}
config.module.rules = config.module.rules.concat([
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
test: /\.css$/,
include: paths.appSrc,
use: [
{
loader: "style-loader" // creates style nodes from JS strings
}, {
loader: "css-loader", // translates CSS into CommonJS
options: {
importLoaders: 1
}
}
]
},
])
config.plugins = config.plugins.concat([
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(env.stringified),
])
config.node = {
console: false,
global: false,
process: false,
Buffer: false,
__filename: false,
__dirname: false,
setImmediate: false,
}
module.exports = config
package.json
{
"name": "universal-create-react-app",
"version": "0.1.0",
"scripts": {
"serve": "NODE_ENV=production node ./build/server/bundle.js",
"start": "node scripts/start.js",
"nodemon": "nodemon --watch build/server build/server/bundle.js build/server/bundle.js",
"build-client": "node scripts/build-client.js",
"build-server": "node scripts/build-server.js",
"build": "npm run build-client && npm run build-server",
"test": "node scripts/test.js --env=jsdom"
},
"author": "Campbell Stephenson: Ahamo Digital - Ahamo Pty Ltd",
"license": "SEE LICENSE IN copyright.txt",
"dependencies": {
"#fortawesome/fontawesome": "^1.1.3",
"#fortawesome/fontawesome-free-brands": "^5.0.6",
"#fortawesome/fontawesome-pro-light": "^5.0.6",
"#fortawesome/fontawesome-pro-regular": "^5.0.6",
"#fortawesome/fontawesome-pro-solid": "^5.0.6",
"#fortawesome/react-fontawesome": "0.0.17",
"axios": "^0.16.2",
"express": "^4.15.3",
"express-http-proxy": "1.0.6",
"i": "^0.3.6",
"npm": "^5.6.0",
"postcss-cssnext": "^3.1.0",
"prop-types": "^15.5.10",
"react": "^16.2.0",
"react-context-component": "^0.0.3",
"react-dom": "^16.2.0",
"react-redux": "^5.0.6",
"react-router-config": "^1.0.0-beta.4",
"react-router-dom": "^4.1.1",
"react-ssr-critical-styles": "^0.1.2",
"reactstrap": "^5.0.0-beta",
"redux": "3.7.2",
"redux-thunk": "2.2.0",
"serialize-javascript": "1.4.0"
},
"devDependencies": {
"autoprefixer": "7.1.0",
"babel-cli": "^6.24.1",
"babel-core": "6.24.1",
"babel-eslint": "7.2.3",
"babel-jest": "20.0.3",
"babel-loader": "^7.1.2",
"babel-preset-react-app": "^3.0.0",
"babel-runtime": "6.23.0",
"case-sensitive-paths-webpack-plugin": "1.1.4",
"chalk": "1.1.3",
"concurrently": "^3.4.0",
"cross-env": "^5.0.0",
"css-loader": "^0.28.9",
"dotenv": "4.0.0",
"eslint": "3.19.0",
"eslint-config-react-app": "^1.0.4",
"eslint-loader": "1.7.1",
"eslint-plugin-flowtype": "2.33.0",
"eslint-plugin-import": "2.2.0",
"eslint-plugin-jsx-a11y": "5.0.3",
"eslint-plugin-react": "7.0.1",
"extract-text-webpack-plugin": "^3.0.2",
"file-loader": "0.11.1",
"fs-extra": "3.0.1",
"html-webpack-plugin": "^2.30.1",
"http-proxy-middleware": "^0.17.4",
"isomorphic-fetch": "^2.2.1",
"isomorphic-style-loader": "^4.0.0",
"jest": "20.0.3",
"node-style-loader": "0.0.1-alpha",
"nodemon": "^1.11.0",
"object-assign": "4.1.1",
"postcss-flexbugs-fixes": "3.0.0",
"postcss-loader": "2.0.5",
"promise": "7.1.1",
"react-dev-utils": "^3.0.0",
"react-error-overlay": "^1.0.7",
"style-loader": "^0.20.1",
"sw-precache-webpack-plugin": "^0.11.4",
"url-loader": "0.5.8",
"webpack": "^3.5.6",
"webpack-dev-server": "^2.8.2",
"webpack-manifest-plugin": "1.1.0",
"webpack-node-externals": "^1.6.0",
"webpack-notifier": "^1.5.1",
"whatwg-fetch": "2.0.3"
},
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx}"
],
"setupFiles": [
"<rootDir>/config/polyfills.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.js?(x)",
"<rootDir>/src/**/?(*.)(spec|test).js?(x)"
],
"testEnvironment": "node",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web"
}
},
"babel": {
"presets": [
"react-app"
]
},
"eslintConfig": {
"extends": "react-app"
}
}
This turned out to not be an issue with Webpack CSS-Loader or any other loader.
It was in fact how I was extending webpack.config.base.js by both webpack.config.client.dev.js and webpack.config.server.js
webpack.config.server.js resulted in it's config being combined with both base and client, hence the same css test being performed twice. This then causes the error:
Module build failed: Unknown word (2:1)
var content = require("!!../../../../../../node_modules/css-loader/index.js?{\"importLoaders\":1}!./styles.css");
if(typeof content === 'string') content = [[module.id, content, '']];
The solution was to use wepack-merge to merge the base file rather than Object.assign({}, base) which to me is a much more elegant solution anyway.
https://www.npmjs.com/package/webpack-merge
Currently I'm struggling to get HMR working in my Webpack 2 setup. I'll explain my entire setup so I hope this is enough for someone to understand what's happening.
The structure of my project:
config
dev.js
prod.js
dist
css
js
index.html
node_modules
src
components
// some JavaScript components
shared
stylesheets
index.js
.babelrc
package.json
webpack.config.js
This are the contents of my webpack.config.js file, placed in the root of my project:
function buildConfig(env) {
return require('./config/' + env + '.js')(env)
}
module.exports = buildConfig;
So in this file I've the option to pass different environments to the buildConfig function. I use this options to use different config files for development and production. This are the contents in my package.json file:
{
"main": "index.js",
"scripts": {
"build:dev": "node_modules/.bin/webpack-dev-server --env=dev",
"build:prod": "node_modules/.bin/webpack -p --env=prod"
},
},
"devDependencies": {
"autoprefixer-loader": "^3.2.0",
"babel-cli": "^6.18.0",
"babel-core": "^6.24.1",
"babel-loader": "^6.2.5",
"babel-preset-latest": "^6.16.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-0": "^6.16.0",
"css-loader": "^0.25.0",
"extract-text-webpack-plugin": "^2.1.0",
"json-loader": "^0.5.4",
"node-sass": "^3.13.1",
"postcss-loader": "^1.3.3",
"postcss-scss": "^0.4.1",
"sass-loader": "^4.1.1",
"style-loader": "^0.13.1",
"webpack": "^2.4.1",
"webpack-dev-server": "^2.4.2"
},
"dependencies": {
"babel-plugin-react-css-modules": "^2.6.0",
"react": "^15.3.2",
"react-dom": "^15.3.2",
"react-hot-loader": "^3.0.0-beta.6",
"react-icons": "^2.2.1"
}
}
I've of course more fields in my package.json but I won't shown them here since they're irrelevant.
So during development I run the npm run build:dev command in my terminal. This will use the file dev.js from the config folder. This are the contents of the dev.js file:
const webpack = require('webpack');
const { resolve } = require('path');
const context = resolve(__dirname, './../src');
module.exports = function(env) {
return {
context,
entry: {
app: [
'react-hot-loader/patch',
// activate HMR for React
'webpack-dev-server/client?http://localhost:3000',
// bundle the client for webpack-dev-server
// and connect to the provided endpoint
'webpack/hot/only-dev-server',
// bundle the client for hot reloading
// only- means to only hot reload for successful updates
'./index.js'
// the entry point of our app
]
},
output: {
path: resolve(__dirname, './../dist'), // `dist` is the destination
filename: '[name].js',
publicPath: '/js'
},
devServer: {
hot: true, // enable HMR on the server
inline: true,
contentBase: resolve(__dirname, './../dist'), // `__dirname` is root of the project
publicPath: '/js',
port: 3000
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.js$/, // Check for all js files
exclude: /node_modules/,
use: [{
loader: 'babel-loader',
query: {
presets: ['latest', 'react'],
plugins: [
[
"react-css-modules",
{
context: __dirname + '/../src', // `__dirname` is root of project and `src` is source
"generateScopedName": "[name]__[local]___[hash:base64]",
"filetypes": {
".scss": "postcss-scss"
}
}
]
]
}
}]
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64]'
}
},
'sass-loader',
{
loader: 'postcss-loader',
options: {
plugins: () => {
return [
require('autoprefixer')
];
}
}
}
]
}
]
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// enable HMR globally
new webpack.NamedModulesPlugin()
// prints more readable module names in the browser console on HMR updates
]
}
};
And last but not least, my HMR setup. I've this setup in my index.js file:
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import TodoApp from './components/TodoApp';
import './stylesheets/Stylesheets.scss';
const render = (Component) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.querySelector('#main')
);
};
render(TodoApp);
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', () => {
render(TodoApp)
});
}
So, when I run my npm start build:dev in my browser and go to http://localhost:3000 I see my site working as expected. This is the output in the console:
dev-server.js:49 [HMR] Waiting for update signal from WDS...
only-dev-server.js:66 [HMR] Waiting for update signal from WDS...
TodoApp.js:102 test
client?344c:41 [WDS] Hot Module Replacement enabled.
The test text comes from the render function in my TodoApp component. This function looks like this:
render() {
console.log('test');
return(
<div styleName="TodoApp">
<TodoForm addTodo={this.addTodo} />
<TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
</div>
);
}
So, now the important stuff. I update the return of this render function, which should trigger the HMR to kick in. I change the render function to this.
render() {
console.log('test');
return(
<div styleName="TodoApp">
<p>Hi Stackoverflow</p>
<TodoForm addTodo={this.addTodo} />
<TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
</div>
);
}
This is the output I get in the console:
client?344c:41 [WDS] App updated. Recompiling...
client?344c:41 [WDS] App hot update...
dev-server.js:45 [HMR] Checking for updates on the server...
TodoApp.js:102 test
log-apply-result.js:20 [HMR] Updated modules:
log-apply-result.js:22 [HMR] - ./components/TodoApp.js
dev-server.js:27 [HMR] App is up to date.
You would say this is good. But my site doesn't update ANYTHING.
Then I change the the HMR code in my index.js to this:
// Hot Module Replacement API
if (module.hot) {
module.hot.accept();
}
And it works. I just don't get it. Why doesn't it work if this is my HMR code:
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', () => {
render(TodoApp)
});
}
BTW this setup is based on the setup from https://webpack.js.org/guides/hmr-react/
I hope that anyone can help me. If someone needs more information don't hesitate to ask. Thanks in advance!
UPDATE
Forgot to post my .babelrc file. This is it:
{
"presets": [
["es2015", {"modules": false}],
// webpack understands the native import syntax, and uses it for tree shaking
"react"
// Transpile React components to JavaScript
],
"plugins": [
"react-hot-loader/babel"
// EnablesReact code to work with HMR.
]
}
The imports are static and after an update has been identified in module.hot.accept you render the exact same component again, as the TodoApp still holds the old version of your module and HMR realises that and doesn't refresh or change anything in your app.
You want to use Dynamic import: import(). To make it work with babel you need to add babel-plugin-syntax-dynamic-import, otherwise it will report a syntax error as it didn't expect import to be used as a function. The react-hot-loader/babel is not needed if you use react-hot-loader/patch in your webpack config, so your plugins in your .babelrc become:
"plugins": [
"syntax-dynamic-import"
]
In your render() function you can now import the TodoApp and render it.
const render = () => {
import('./components/TodoApp').then(({ default: Component }) => {
ReactDOM.render(
<AppContainer>
<Component />
</AppContainer>,
document.querySelector('#main')
);
});
};
render();
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp', render);
}
import() is a promise that will resolve with the module, and you want to use the default export.
Even though the above is true, the webpack documentation doesn't require you to use dynamic imports, because webpack handles ES modules out of the box, also described in react-hot-loader docs - Webpack 2, and because webpack is also handling the HMR, it will know what to do in that case. For this to work, you must not transform the modules to commonjs. You did this with ["es2015", {"modules": false}], but you also have the latest preset configured in your webpack config, which also transforms the modules. To avoid confusion, you should have all babel configurations in .babelrc instead of splitting some to the loader options.
Remove the presets in the babel-loader entirely from your webpack config and it will work as you already have the necessary presets in your .babelrc. babel-preset-latest is deprecated and if you want to use these features you should start using babel-preset-env which also replaces es2015. So your presets in .babelrc would be:
"presets": [
["env", {"modules": false}],
"react"
],
Check this issue on GitHub or just use this in your index.js:
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'
import App from './components/App'
const render = Component => {
ReactDOM.render(
<AppContainer>
<Component/>
</AppContainer>,
document.getElementById('react-root')
)
}
render(App)
if(module.hot) {
module.hot.accept();
}