I've just switched to Preact 8.4.2 and would like to get the React Developer Tools to work as well. In my webpack.config.js, I've added:
alias: {
react: 'preact-compat',
'react-dom': 'preact-compat'
}
In my entry .js file, I've added:
require('preact/debug');
After adding these, I was getting an error when attempting to build:
Module parse failed: /myProject/node_modules/preact/src/preact.js Line 1: Unexpected token
You may need an appropriate loader to handle this file type.
| import { h, h as createElement } from './h';
| import { cloneElement } from './clone-element';
| import { Component } from './component';
# ./~/preact/debug.js 6:14-31
I only had .jsx files loading with babel-loader (not .js), so I added an additional entry in my webpack.config.js file:
{
test: /\.js$/,
include: /node_modules\/preact/,
loader: 'babel-loader'
},
After adding this entry, I'm able to build without issues, but my React Developer Tools just shows:
Waiting for roots to load...
to reload the inspector [click here]
Something is either up with your preact app or your webpack config. I just solved a similar problem.
First step, check if its your preact. If you have no console errors, drop your preact into this working boilerplate (you'll have to do a little rewiring to get it working) https://github.com/developit/preact-boilerplate
If after firing it up with your code, Devtools works as expected, then there is something wrong with your build. In that case it turns into a game of line by line updating your (mostly) working build to match preact-boilerplate.
In my case, I had included "src" in my webpack resolve. This threw no errors in terminal/console, and the build worked perfectly otherwise. Once I found it, devtools started working.
Related
Summary of problem
I'm exclusively using ESM in my Node.js project and trying to find a way to dynamically import JSX.
I'm making a custom static site generator for my website and want to render React components to markup with renderToStaticMarkup(), but to achieve this, I first need to successfully import the components to then run this method.
Does anyone know a way to dynamically import JSX in ESM Node.js?
I.e., to make await import("./jsxComponent.js") work?
A few things I've tried
Approach 1: Direct attempt
When I dynamically import the .js file containing the component, I receive the error message: SyntaxError: Unexpected token '<'. Seems import() cannot parse JSX out of the box.
If I change the file extension of the .js file to .jsx, I unsurprisingly receive the error message Unknown file extension ".jsx".
Approach 2: Babeling
Back in the CommonJS heyday of Node.js, I'd use #babel/register, #babel/preset-env, and #babel/preset-react in a separate file with its last line invoking require() on another .js file that, inside itself, would then require() the component. I'm not entirely clued up on how each Babel preset or plugin works, but this did the trick back then allowing me to require() components to then render them to markup. Unfortunately, this doesn't work when using ESM-only packages in an ESM-only project because the moment I use #babel/register my ESM-only packages complain and break.
I've tried using #babel/core to transform the file before it's invoked inside import(). I've done this by using the transformFileSync method, but this created the error message: Error [ERR_MODULE_NOT_FOUND]: Cannot find package '"use strict". Inside the options object of transformFileSync I used babel-plugin-dynamic-import-node as a plugin and #babel/register, #babel/preset-env, and #babel/preset-react as presets.
I've tried also using #babel/core's transformSync method by passing in the JSX code directly (rather than just the file path of the JSX-containing file), and this created the error message: Error: ENOENT: no such file or directory, open 'import Header from "./src/components/header.js"; (note: there IS a file at ./src/components/header.js - it is one of the components being imported inside another component.)
Approach 3: Require
Other approaches online recommend using require() instead of import(), but as I said, this is an ESM-only project using ESM-only packages and so the error message I receive when trying this is require is not defined, as one would expect.
Code examples
Approach 1: Direct attempt
const module = await import("./jsxComponent.js")
Approach 2: Babeling
const module = await import(
babelCore.transformFileSync("./jsxComponent.js", {
presets: [
"#babel/preset-env",
[
"#babel/preset-react",
{
runtime: "automatic",
},
],
],
plugins: ["dynamic-import-node"],
}).code
);
(Let me know if you want me to post any more code examples from my tests with Babel).
Approach 3: Require
const module = require("./jsxComponent.js")
I was able to import JSX in my ESM-only project by:
Installing #node-loader/babel (see GitHub repo)
Installing #babel/core and #babel/preset-react
Creating babel.config.js in my root directory with the following setup:
export default {
presets: [
[
"#babel/preset-react",
{
runtime: "automatic",
},
],
],
};
Then running my node build script with the node loader set as an experimental loader: node --experimental-loader #node-loader/babel ./lib/build.js
I was then able to successfully use const component = await import("./jsxComponent.js") in my node build scripts and pass the component to reactDOMServer's renderToStaticMarkup(component()) method by invoking it as a function.
I'm getting an error from one of my (previously working) tests when I run yarn jest:
Cannot find module 'got' from 'src/rss/queries.ts'
I've added got in package.json:
"devDependencies": {
"got": "^12.0.0",
}
My jest.config.js:
module.exports = {
preset: 'ts-jest',
testMatch: ['**/*.test.ts(|x)'],
collectCoverageFrom: ['**/*.ts', '!.webpack/**/*'],
verbose: true,
}
I'm using got in ./src/rss/queries.ts:
import * as got from 'got'
I've also tried:
import { got, RequestError } from 'got'
In both cases the application works - I can see got making requests via the application logs (and vscode is indicating the correct path to the module in node_modules when I hover over the above). So it's definitely there, and working.
But jest can't find it. Why? It's not an uncommon stackoverflow question, but they all seem to relate to importing custom local modules via relative paths, etc. I'm just trying to use one out of node_modules...
Version 12 of got doesn't work with jest. Best to use version 11 for now. See the details in the release notes at: https://github.com/sindresorhus/got/releases/tag/v12.0.0
Wasn't able to find a reason for, or solution to, this. Ended up swapping got for axios, which is a shame as I liked many got features.
My Visual Studio Code extension uses the node module highlight.js which comes with a folder full of CSS files. These provide colour schemes for syntax colouring. It has become necessary to bundle some of the CSS files.
It's about bundling an asset
The objective is to bundle a CSS file and at run-time access the file content as a string. If that can be achieved without an import statement that would be perfect. Normally, how exactly one accesses the content of the bundled file would be a separate question, but I have a feeling that content retrieval and how one should go about bundling the asset are closely entwined.
I freely admit to having a weak understanding of WebPack.
The story so far
The bundler is specified in package.json as "webpack": "^5.4.0" but I don't know how to ascertain what is actually present. It is conceivable that there is something wrong with my setup: when I try to run webpack --version on a command prompt in the project folder, it responds
CLI for webpack must be installed.
webpack-cli (https://github.com/webpack/webpack-cli)
We will use "npm" to install the CLI via "npm install -D webpack-cli".
Do you want to install 'webpack-cli' (yes/no):
The first time this happened I responded yes. After a flurry of installation and another try the same thing happened. However, vsce package has no trouble using webpack for a production build and pressing F5 to debug successfully puts together a development build in a dist folder with an unminified file I can examine (which is how I know the file mentioned below is being bundled).
Moving on from there I've modified webpack.config.js like so
//#ts-check
'use strict';
const path = require('path');
/**#type {import('webpack').Configuration}*/
const config = {
target: 'node', // vscode extensions run in a Node.js-context -> https://webpack.js.org/configuration/node/
entry: './src/extension.ts', // the entry point of this extension, -> https://webpack.js.org/configuration/entry-context/
output: {
// the bundle is stored in the 'dist' folder (check package.json), -> https://webpack.js.org/configuration/output/
path: path.resolve(__dirname, 'dist'),
filename: 'extension.js',
libraryTarget: 'commonjs2',
devtoolModuleFilenameTemplate: '../[resource-path]'
},
devtool: 'source-map',
externals: {
vscode: 'commonjs vscode' // the vscode-module is created on-the-fly and must be excluded. Add other modules that cannot be webpack'ed, -> https://webpack.js.org/configuration/externals/
},
resolve: {
// support reading TypeScript and JavaScript files, -> https://github.com/TypeStrong/ts-loader
extensions: ['.ts', '.js', '.css']
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
{
loader: 'ts-loader'
}
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
};
module.exports = config;
As you can see there are rules and loaders for CSS.
When I add this import
import "../node_modules/highlight.js/styles/atelier-dune-light.css";
webpack happily builds the bundle and when I inspect it I can find the bundled CSS.
However, when I try to load the extension in the extension debug host, it fails to load, with this message.
Activating extension 'pdconsec.vscode-print' failed: document is not defined.
Enabling break on caught exceptions reveals this rather surprising exception.
Exception has occurred: Error: Cannot find module 'supports-color'
Require stack:
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\node_modules\debug\src\node.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\node_modules\debug\src\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\get-uri\dist\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\vscode-proxy-agent\out\agent.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\node_modules.asar\vscode-proxy-agent\out\index.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-amd.js
- c:\Users\Peter\AppData\Local\Programs\Microsoft VS Code\resources\app\out\bootstrap-fork.js
OK, so activation failed because the loader barfed. But WTF does importing CSS have to do with support-color?
Remove the import and it runs just fine. I really don't know how to respond to this; it's not clear to me why a demand for a stylesheet should cause that error. At this point I look to others for guidance and advice.
Remove style-loader from webpack.config.js to fix the error.
Pull the CSS as a string like this. Note the abbreviated path.
const cssPath: string = "highlight.js/styles/atelier-dune-light.css";
const theCss: string = require(cssPath).default.toString();
You do not need the import statement, the use of require will cause Webpack to bundle the files, but you still have to remove style-loader to avoid the loader error.
I try to import a node module inside an Angular 8 web worker, but get an compile error 'Cannot find module'. Anyone know how to solve this?
I created a new worker inside my electron project with ng generate web-worker app, like described in the above mentioned ng documentation.
All works fine until i add some import like path or fs-extra e.g.:
/// <reference lib="webworker" />
import * as path from 'path';
addEventListener('message', ({ data }) => {
console.log(path.resolve('/'))
const response = `worker response to ${data}`;
postMessage(response);
});
This import works fine in any other ts component but inside the web worker i get a compile error with this message e.g.
Error: app/app.worker.ts:3:23 - error TS2307: Cannot find module 'path'.
How can i fix this? Maybe i need some additional parameter in the generated tsconfig.worker.json?
To reproduce the error, run:
$ git clone https://github.com/hoefling/stackoverflow-57774039
$ cd stackoverflow-57774039
$ yarn build
Or check out the project's build log on Travis.
Note:
1) I only found this as a similar problem, but the answer handles only custom modules.
2) I tested the same import with a minimal electron seed which uses web workers and it worked, but this example uses plain java script without angular.
1. TypeScript error
As you've noticed the first error is a TypeScript error. Looking at the tsconfig.worker.json I've found that it sets types to an empty array:
{
"compilerOptions": {
"types": [],
// ...
}
// ...
}
Specifying types turns off the automatic inclusion of #types packages. Which is a problem in this case because path has its type definitions in #types/node.
So let's fix that by explicitly adding node to the types array:
{
"compilerOptions": {
"types": [
"node"
],
// ...
}
// ...
}
This fixes the TypeScript error, however trying to build again we're greeted with a very similar error. This time from Webpack directly.
2. Webpack error
ERROR in ./src/app/app.worker.ts (./node_modules/worker-plugin/dist/loader.js!./src/app/app.worker.ts)
Module build failed (from ./node_modules/worker-plugin/dist/loader.js):
ModuleNotFoundError: Module not found: Error: Can't resolve 'path' in './src/app'
To figure this one out we need to dig quite a lot deeper...
Why it works everywhere else
First it's important to understand why importing path works in all the other modules. Webpack has the concept of targets (web, node, etc). Webpack uses this target to decide which default options and plugins to use.
Ordinarily the target of a Angular application using #angular-devkit/build-angular:browser would be web. However in your case, the postinstall:electron script actually patches node_modules to change that:
postinstall.js (parts omitted for brevity)
const f_angular = 'node_modules/#angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js';
fs.readFile(f_angular, 'utf8', function (err, data) {
var result = data.replace(/target: "electron-renderer",/g, '');
var result = result.replace(/target: "web",/g, '');
var result = result.replace(/return \{/g, 'return {target: "electron-renderer",');
fs.writeFile(f_angular, result, 'utf8');
});
The target electron-renderer is treated by Webpack similarily to node. Especially interesting for us: It adds the NodeTargetPlugin by default.
What does that plugin do, you wonder? It adds all known built in Node.js modules as externals. When building the application, Webpack will not attempt to bundle externals. Instead they are resolved using require at runtime. This is what makes importing path work, even though it's not installed as a module known to Webpack.
Why it doesn't work for the worker
The worker is compiled separately using the WorkerPlugin. In their documentation they state:
By default, WorkerPlugin doesn't run any of your configured Webpack plugins when bundling worker code - this avoids running things like html-webpack-plugin twice. For cases where it's necessary to apply a plugin to Worker code, use the plugins option.
Looking at the usage of WorkerPlugin deep within #angular-devkit we see the following:
#angular-devkit/src/angular-cli-files/models/webpack-configs/worker.js (simplified)
new WorkerPlugin({
globalObject: false,
plugins: [
getTypescriptWorkerPlugin(wco, workerTsConfigPath)
],
})
As we can see it uses the plugins option, but only for a single plugin which is responsible for the TypeScript compilation. This way the default plugins, configured by Webpack, including NodeTargetPlugin get lost and are not used for the worker.
Solution
To fix this we have to modify the Webpack config. And to do that we'll use #angular-builders/custom-webpack. Go ahead and install that package.
Next, open angular.json and update projects > angular-electron > architect > build:
"build": {
"builder": "#angular-builders/custom-webpack:browser",
"options": {
"customWebpackConfig": {
"path": "./extra-webpack.config.js"
}
// existing options
}
}
Repeat the same for serve.
Now, create extra-webpack.config.js in the same directory as angular.json:
const WorkerPlugin = require('worker-plugin');
const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin');
module.exports = (config, options) => {
let workerPlugin = config.plugins.find(p => p instanceof WorkerPlugin);
if (workerPlugin) {
workerPlugin.options.plugins.push(new NodeTargetPlugin());
}
return config;
};
The file exports a function which will be called by #angular-builders/custom-webpack with the existing Webpack config object. We can then search all plugins for an instance of the WorkerPlugin and patch its options adding the NodeTargetPlugin.
I'm getting an error when running my react app: Uncaught SyntaxError: Unexpected token import
I know that there are a plethora of similar issues on here, but I think mine is a little different. First of all, here is the repository, since I'm not sure where exactly the error is: repo
I'm using create-react-app, and in a seperate backend directory I'm using babel (with a .babelrc file containing the preset es2015). The app worked fine until I added another file in a new directory in the backend folder (/backend/shared/validations/signup.js).
I was using es6 before that too, and it was working perfectly fine. First I thought it was some problem with windows, but I cloned the repo on my Ubuntu laptop and I'm getting the same error there.
Some things I tried already:
Move the entire folder from /backend to the root folder
Move just the file (signup.js) just about everywhere
So no matter where the file is, the error stays the same. If I remove the entire file and all references to it the app works again.
I think this error is pretty weird, considering I'm using es6 everywhere else in the app without trouble. It would be great if anyone could help me with this error.
edit: If you want to test this on your own machine just clone the repo and run npm start in the root folder (and also npm start in the backend folder, but that isn't required for the app to run, or for the error to show up).
That's what's happening:
Your webpack is set to run babel loader only in the src folder (include directive).
To change that, one approach is:
1) extract webpack configuration with npm run eject (don't know if there is another way to override settings in react-create-app). From the docs:
Running npm run eject copies all the configuration files and the
transitive dependencies (Webpack, Babel, ESLint, etc) right into your
project so you have full control over them.
2) in config/paths.js, add an appShared key, like that:
module.exports = {
/* ... */
appSrc: resolveApp('src'),
appShared: resolveApp('backend/shared'),
/* ... */
};
3) in config/webpack.config.dev.js, add the path to the babel loader, like that:
{
test: /\.(js|jsx)$/,
include: [ paths.appSrc, paths.appShared ],
loader: 'babel',
/* ... */
},
It works now!