How is webpack-cli used in a project?
From what I understand, as soon as I enter npm run start on my bash terminal, webpack starts running the webpack config file where I have written rules to convert jsx to js using babel, scss/less to css (correct me if I'm wrong).
But where does webpack-cli comes into play in all this?
The webpack-dev-server package is responsible to serve the build over an http server that it creates for it. It also re-starts if you make any changes to the source code (when using the hot reload option).
On the other hand, the webpack-cli package is responsible for the build and bundle of the source files. So, webpack-dev-server has to run the webpack-cli.
So you've got to have both of the packages installed.
You can see kind of how it does that in here:
https://github.com/webpack/webpack-dev-server/blob/master/bin/webpack-dev-server.js
/** #type {CliOption} */
const cli = {
name: 'webpack-cli',
package: 'webpack-cli',
binName: 'webpack-cli',
installed: isInstalled('webpack-cli'),
url: 'https://github.com/webpack/webpack-cli',
preprocess() {
process.argv.splice(2, 0, 'serve');
},
};
// ...
const runCli = (cli) => {
if (cli.preprocess) {
cli.preprocess();
}
const path = require('path');
const pkgPath = require.resolve(`${cli.package}/package.json`);
// eslint-disable-next-line import/no-dynamic-require
const pkg = require(pkgPath);
// eslint-disable-next-line import/no-dynamic-require
require(path.resolve(path.dirname(pkgPath), pkg.bin[cli.binName]));
};
// ...
runCommand(packageManager, installOptions.concat(cli.package))
.then(() => {
runCli(cli);
})
.catch((error) => {
console.error(error);
process.exitCode = 1;
});
In webpack v5, that order kind of got reversed since you use webpack server, which is a webpack-cli call, to initiate the serve, that will call the webpack-dev-server package.
I'm not a webpack expert by any means, but I think this will help you to understand it better.
Related
I've made a cra-template which could be installed by npx command.
Npx command goes to <rootDir>/bin/cli.js and it imports chalk#4.1.2
On local environment it works very well(node bin/cli.js <my-app-name>)
But whenever I try to install by npx create-... <my-app-name> it always alert error below
Need to install the following packages:
create-...#latest
Ok to proceed? (y) y
------------------------------------------------------------------------
node:internal/errors:465
ErrorCaptureStackTrace(err);
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find package 'chalk' imported from
/<to .npm>/.npm/_npx/<my npx hash>/node_modules/<create-...>/bin/cli.mjs
❌ I've changed my cli.js file to cli.mjs cause of Chalk 5 has changed to ESM
❌ I downgraded chalk#5 to chalk#4.1.2. It doesn't work at all with same issue
❌ I also changed cli.mjs to cli.js which allows const..require.. with chalk#4.1.2
ONLY WHEN I ACCESS TO /<to .npm>/.npm/_npx/<my npx hash> and npm i chalk#4.1.2 IT WORKS
I'm facing this issue about 3days. I tried to find out "How npx command works", "Chalk >issues", "Error code:465" etc...
This issue is way over my head. Please be my life saver.......
Here's my code
// <rootDir>/bin/cli.js
#!/usr/bin/env node
import { execSync } from "child_process";
import { fileURLToPath } from "url";
import chalk from "chalk";
import path from "path";
const runCommand = (command) => {
try {
execSync(`${command}`, { stdio: "inherit" });
return true;
} catch (err) {
console.log(`Failed to run ${command}`);
console.log(err);
return false;
}
};
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const dirName = process.argv[2];
const gitCheckoutCommand = `git clone --depth 1 <my git repo>;
const npmInstallCommand = `cd ${dirName} && npm install`;
// Create new create-react-app-lite
console.log(
chalk.blueBright(`Creating a new React app in`),
chalk.magentaBright.bold.italic.underline(
`${path.resolve(process.cwd(), `../../../../${dirName}`)}`,
),
);
const checkedOut = runCommand(gitCheckoutCommand);
if (!checkedOut) {
process.exit(1);
}
// Install dependencies
... console.log() command with chalk
// Inform success and commands to start, build, test, prettier, and lint
... console.log() command with chalk
I am trying to run cypress test cases headless using cmd command
npx cypress run
But it gives me below error -
Do I need to install any dependency for this to load.
Even css files are not getting loaded.
Note : I haven't installed webpack or any other dependency. Only cypress is installed additionally.
Yes, you will need to extend the webpack configuration used by cypress to handle the files you would like to load. You can find an example here
Below I've modified the example to work with cypress 10.
// cypress.config.ts
import { defineConfig } from 'cypress';
import findWebpack from 'find-webpack';
import webpackPreprocessor from '#cypress/webpack-preprocessor';
const webpackOptions = findWebpack.getWebpackOptions();
const options = {
webpackOptions,
watchOptions: {},
};
export default defineConfig({
e2e: {
setupNodeEvents(on) {
// implement node event listeners here
// on('file:preprocessor', webpack(options));
// use a module that carefully removes only plugins
// that we found to be breaking the bundling
// https://github.com/bahmutov/find-webpack
const cleanOptions = {
reactScripts: true,
};
findWebpack.cleanForCypress(cleanOptions, webpackOptions);
on('file:preprocessor', webpackPreprocessor(options));
},
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
},
});
I am trying to set up Storybook in a project. My project is runing on react#^16, and I'm using typescript, with a custom babel and webpack setup for development and build. To set up storybook, I did
npx sb init
This installs everything needed. It puts a .storybook folder in the root folder, and a stories folder in my src folder with some prefab components and stories in tsx format (which is what I want):
The .storybook/main.js file seems fine:
module.exports = {
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
],
"addons": [
"#storybook/addon-links",
"#storybook/addon-essentials"
]
}
And the average .stories.js file automatically installed by npx sb init also seems fine:
import React from 'react';
// also exported from '#storybook/react' if you can deal with breaking changes in 6.1
import { Story, Meta } from '#storybook/react/types-6-0';
import { Header, HeaderProps } from './Header';
export default {
title: 'Example/Header',
component: Header,
} as Meta;
const Template: Story<HeaderProps> = (args) => <Header {...args} />;
export const LoggedIn = Template.bind({});
LoggedIn.args = {
user: {},
};
export const LoggedOut = Template.bind({});
LoggedOut.args = {};
But when I run npm run storybook, the storybook landing page has no stories. Even though it had installed some default stories to start playing with. It says:
Oh no! Your Storybook is empty. Possible reasons why:
The glob specified in main.js isn't correct.
No stories are defined in your story files.
As requested, here is a link to the repo so you can dig a bit deeper into the structure, weback config, etc. Note I have not committed the npx sb init changes yet, so you won't see the files there, only my starting point just before running the sb init.
I haven't had any issues getting npx sb init to work with a standard create-react-app, but with my custom webpack build and typescript, its just empty. What's going wrong?
Edit: Additional detail
I realize that just running npx sb init, then npm run storybook throws this error:
ERROR in ./.storybook/preview.js-generated-config-entry.js
Module not found: Error: Can't resolve 'core-js/modules/es.array.filter'
Based on this thread, installing core-js#3 solves the problem and storybook runs, though with no stories.
It seems like the babel plugin transform-es2015-modules-amd doesn't fit right with storybook since sb still uses your babel configuration.
You might need to remove it then it would work:
{
"plugins": [
// "transform-es2015-modules-amd", // Remove this plugin
]
}
If you want to have a special babel configuration for storybook, place it .storybook/.babelrc so the configuration would be simple like this:
.storybook/.babelrc:
{
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-typescript"]
}
NOTE: You might miss to forget install #babel/preset-typescript to help you transform your typescript code.
Maybe you have problems with the stories path, try to save only "../src/**/*.stories.js" in your config to see if its the reason
"stories": [
"../src/**/*.stories.mdx",
"../src/**/*.stories.#(js|jsx|ts|tsx)"
]
In case of dealing with arcgis-js-api in sb, you have to declare #arcgis/webpack-plugin in storybook's webpack configuration by adding to its config.
Here are a few steps you have to do:
Add webpackFinal property in .storybook/main.js with following content:
const ArcGISPlugin = require('#arcgis/webpack-plugin');
module.exports = {
// ...
webpackFinal: (config) => {
// Add your plugin
config.plugins.push(
new ArcGISPlugin(),
);
// Since this package has used some node's API so you might have to stop using it as client side
config.node = {
...config.node,
process: false,
fs: "empty"
};
return config;
}
};
One more thing to be aware of, some components are importing scss files, so you might need to support it by adding a scss addon '#storybook/preset-scss'
// Install
npm i -D #storybook/preset-scss css-loader sass-loader style-loader
// Add to your current addons
{
addons: ['#storybook/addon-links', '#storybook/addon-essentials', '#storybook/preset-scss'],
}
Like a tmhao2005 say. Storybook still uses your babel configuration. And this is the intended behavior. This thread at github also describes how the fix similar issue.
Updated your config .storybook/main.js.
If you use .babelrc:
babel: async options => ({ ...options, babelrc: false })
Or .babel.config.js:
babel: async options => ({ ...options, configFile: false })
I'm trying to create a worker in an app created from create-react-app using react 16.8.6 and yarn 1.16.0. If I use
const backgroundWorker = new Worker('../assets/js/myWorker.js');
I get the console error: Uncaught SyntaxError: Unexpected token <
But I know that is the correct path. This works fine in Angular. Is there a good tutorial on how to create a worker in React?
The directory "assets" is the public directory for #angular/cli projects, not create-react-app projects. In create-react-app the equivalent of #angular/cli "assets" is "public" which is described in the create-react-app documentation under Using the Public Folder. Move your "js" directory and the "myWorker.js" file to the public directory and update the creation of the worker to point to that path instead:
const backgroundWorker = new Worker('/js/myWorker.js');
You can also use process.env.PUBLIC_URL instead:
const backgroundWorker = new Worker(`${process.env.PUBLIC_URL}/js/myWorker.js`);
Hopefully that helps!
Follow these steps in order to add your worker files to your create-react-app project.
1. Install these three packages:
$ yarn add worker-plugin --dev
$ yarn add comlink
$ yarn add react-app-rewired --dev
2. Override webpack config:
In your project's root directory create a config-overrides.js file with the following content:
const WorkerPlugin = require("worker-plugin");
module.exports = function override(config, env) {
//do stuff with the webpack config...
config.plugins = [new WorkerPlugin({ globalObject: "this"}), ...config.plugins]
return config;
}
3. Replace your npm scripts inside package.json by:
"start": "react-app-rewired start",
"build": "react-app-rewired build",
4. Create two files in order to test your configuration:
worker.js
import * as Comlink from "comlink";
class WorkerWorld {
sayHello() {
console.log("Hello! I am doing a heavy task.")
let numbers = Array(500000).fill(5).map(num => num * 5);
return numbers;
}
}
Comlink.expose(WorkerWorld)
use-worker.js
import * as Comlink from "comlink";
const initWorker = async () => {
const workerFile = new Worker("./worker", { name: "my-worker", type: "module" });
const WorkerClass = Comlink.wrap(workerFile)
const instance = await new WorkerClass();
const result = await instance.sayHello();
console.log("Result of my worker's computation: ", result);
}
initWorker()
5. See the output:
$ yarn start
If you build your project with NODE_ENV=production, react automatically includes the minified production verison of the lib in the bundle. Conversely, a non production build will include the dev unminified version of react.
How is this being achieved?
If we install react:
npm install --save react
Then look at its package.json for the main key, it points to:
"main": "react.js",
Looking at react.js the contents of the file are simply:
module.exports = require('./lib/React');
Looking in ./lib/React I was expecting to see a conditional that loaded the minified build or not, but the conditionals seem to do other stuff:
if (process.env.NODE_ENV !== 'production') {
var ReactElementValidator = require('./ReactElementValidator');
createElement = ReactElementValidator.createElement;
createFactory = ReactElementValidator.createFactory;
cloneElement = ReactElementValidator.cloneElement;
}
var __spread = _assign;
if (process.env.NODE_ENV !== 'production') {
var warned = false;
__spread = function () {
process.env.NODE_ENV !== 'production' ? warning(warned, 'React.__spread is deprecated and should not be used. Use ' + 'Object.assign directly or another helper function with similar ' + 'semantics. You may be seeing this warning due to your compiler. ' + 'See fb.me/react-spread-deprecation for more details.') : void 0;
warned = true;
return _assign.apply(null, arguments);
};
}
What is react doing exactly between prod and dev builds? It doesn't seem like it interacts with the minified and unminified builds in /dist as I thought.