How to configure Stylus support in a React.js application? - javascript

I want the classes in my React.js application to be available for export from .styl-files in the same way as it can be done from CSS Modules, but I can't find any ready-made solution to this problem.
I found a guide to setting up CSS Modules in an application created with Create React App.
I understand that you need to run npm run eject and somehow rewrite configuration files,
but how – I don't understand.

You need to install next npm-packages in your project:
stylus
stylus-loader
css-loader
In webpack.config, in section module you need to add next points:
{
test: /\.styl$/,
use: [
'style-loader',
'css-loader?modules&camelCase&localIdentName=[path]__[name]__[local]--[hash:base64:5]',
'stylus-loader',
],
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
],
},
Then you can import your styles from .styl files in your React components like this:
import style from './СomponentStyle.styl';
and you can use style by CSS name for example:
className={style.container}
where container - it is name of CSS but without dot. For complicated names like: .container-btn-green you need write next code: style.containerBtnGreen or style['container-btn-green']

Run-time solution ( without eject )
install react-rewired and customize-cra to have an option to update config on run-time
npm i react-app-rewired
npm i customize-cra
create file config-overrides.js in the package.json folder with content :
const {
override,
addWebpackModuleRule
} = require("customize-cra");
module.exports = override(
addWebpackModuleRule({
test: /\.styl$/,
exclude: /(node_modules)/,
loaders: [
'style-loader',
{
loader: 'css-loader',
options: {url: false}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: (loader) => [require('autoprefixer')()]
}
},
'stylus-loader'
]
}),
addWebpackModuleRule({
test: /\.css$/,
use: [
'style-loader',
'css-loader',
]
})
);
install stylus
npm i stylus
npm i stylus-loader
npm i css-loader
change your start / build scripts to use react-rewired
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
...
Then you can import your styles from .styl files in your React components
require('./style/index.styl');
OR
import style from './СomponentStyle.styl'; --> className={style.container}
This all :) Additional thanks to Denis Bubnov in current topic - you helped me much to implement current solution!

Here is the link to configure stylus with create react app
https://github.com/flexzuu/create-react-app-styl

I like Surya's approach.
install stylus with
npm install stylus --save-dev
Create 2 folders /src/styl and /src/css
Drop some files into /src/styl.
Add the following scripts to your package.json:
"stylus:watch": "stylus -I ./node_modules -w ./src/styl -o ./src/css",
"stylus": "stylus -I ./node_modules ./src/styl -o ./src/css"
Run npm run stylus:watch in a second terminal. It will watch all files in /src/styl and compile them to css in /src/css where they will be picked up by your React dev server.
Before building your react app, make sure to run npm run stylus one last time.

Possible solution
Install stylus globally (just like it is described on their official website)
npm install stylus -g
Modify your build script in package.json
Mac/Ubuntu:
"scripts": {
"build:stylus": "find . -name *.styl -exec stylus {} --out ./build/static/css ;",
"build": "react-scripts build && npm run build:stylus",
}
Windows:
"scripts": {
"build:stylus": "for /r %v in (*.styl) do stylus %v --out ./build/static/css",
"build": "react-scripts build && npm run build:stylus",
}
In the scripts above we are calling the stylus command described below:
stylus <path-to-input-file.styl> --out <path-to-output-file\>

Related

How to deal with external modules when compiling TypeScript?

I am very new to TypeScript and I am trying out many things and got stuck with external modules after compilation.
I started with simple TypeScript project in Visual Studio Code set to target ES2015 and module to es2015 (because I want to use native stuff as much as possible) and I wanted to try Strongly Type Events (STE) which I installed using npm.
By changing module resolution to node and setting baseUrl in tsconfig.json, TypeScript has no problem in using STE with non-relative import:
import { SimpleEventDispatcher } from "ste-simple-events";
However, when I compile TypeScript, resulting JavaScript file has exact same import statement and when loading html which is including this module, I get an error that module cannot be found.
I can not figure out how to solve this.
Should TypeScript somehow change import statement to exact location of STE?
Perhaps, but TypeScript team says TypeScript compilation will never change code in import statements.
Or should I somehow compile external modules as well, so that they get included in output?
Or should default module resolution in ES2015 standard implemented in browsers do the job - for which I have no idea how it works and how should external ES2015 modules be imported in JavaScript?
Any help or a nudge in the right direction would be greatly appreciated.
Thanks,
Mario
For any TypeScript beginner scratching their head over this, the answer is called JavaScript bundlers.
Since I am using ES6, I opted for RollupJs bundler combined with following plugins (use them in this order):
rollup-plugin-resolve - required to resolve node_modules
rollup-plugin-commonjs - required to transpile CommonJS modules in node_modules to ES6
rollup-plugin-typescript2 - optional, you can have it in the process or you can use tsc manually before you run rollup - just make sure you use version 2 (first version is not maintained any more)
rollup-plugin-terser - minifier and obfuscator
You can install all of those with npm:
npm install rollup rollup-plugin-resolve rollup-plugin-commonjs rollup-plugin-typescript2 rollup-plugin-terser
Add rollup.config.js to the root of your project, mine looked like this:
import typescript from "rollup-plugin-typescript2"
import commonjs from "rollup-plugin-commonjs";
import resolve from "rollup-plugin-node-resolve";
import { terser } from "rollup-plugin-terser";
import pkg from "./package.json"
export default {
input: "./wwwroot/js/svgts.js",
output: [
{
file: pkg.module,
format: "esm",
},
],
external: [
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
], plugins: [
resolve({
mainFields: ["module"], // Default: ["module", "main"]
}),
commonjs({
include: "node_modules/**"
}),
typescript({
typescript: require("typescript"),
tsconfig: "./tsconfig.json"
}),
(process.env.NODE_ENV === "production" && terser({
mangle: { reserved: ['svg'] }
}))
],
}
Rollup supports environment variables which I use here with line:
process.env.NODE_ENV === "production"
This allows you to create npm scripts in package.json to easily include minification or not, for example:
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"rollup": "rollup -c",
"rollupw": "rollup -cw",
"start": "concurrently \"npm run rollupw\" \"npm run lite\"",
"startprod": "NODE_ENV=production concurrently \"npm run rollupw\" \"npm run lite\"",
"production": "NODE_ENV=production npm run rollup"
},
Then you can run in terminal npm run production for instance to build minified bundle.
You can find more details on GitHub of each project.

Babel does not find a plugin

I have an app module and common module that is shared by several app modules.
- app
- src
- package.json
- webpack.config.json
- .babelrc
- common
- lib
- package.json
- .babelrc
app/package.json
dependencies: {
common: "../common"
},
devDependencies: {
...othe deps,
"babel-plugin-transform-object-rest-spread": "^6.23.0",
}
common/package.json
devDependencies: {
..other deps,
"babel-plugin-transform-object-rest-spread": "^6.23.0",
}
common code is in es6 and needs to be transpiled in app so webpack.config.js contains
{
test: /\.js/,
exclude: /node_modules\/(?!(ui-common|ui-server-common)\/).*/,
loader: 'babel-loader',
},
Everything works fine if I run yarn install in common module, then in app module. That copies complete node_modules of common module so it contains all dev deps including babel-plugin-transform-object-rest-spread.
If I remove node_modules from common module, run yarn install app module, only prod dependencies are copied and babel-plugin-transform-object-rest-spread is missing in app/node_modules/common/node_modules. I then get
Module build failed: ReferenceError: Unknown plugin "transform-object-
rest-spread" specified in "/Users/blaf/projects/management-
ui/ui-common/.babelrc" at 0, attempted to resolve relative to
"/Users/blaf/projects/management-ui/ui-common"
because babel-plugin-transform-object-rest-spread is missing in app/node_modules/common/node_modules. The package is already in app/node_modules so there should be no problem but babel wants it right in the common package? How can I tell babel to use the root level dependency?

Webpack: How to compile, write on disk and serve static content (js/css) using webpack-dev-server

I want to build my js/css code, write it on disk and serve it using webpack-dev-server in a single command. I don't want to set-up another server for production mode. How do we do it? Sharing my webpack.config.js file content below:
module.exports = {
watch: true,
entry: [
'./src/index.js'
],
output: {
path: __dirname +'/dist/',
publicPath: '/dist/',
filename: 'bundle.js'
},
module: {
loaders: [
{
exclude:/(node_modules)/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
Please find the start script used in package.json below:
"start": "webpack-dev-server --progress --colors"
I am running "npm run start". Please help.
New webpack-dev-server is released, and it supports writeToDisk option.
devServer: {
writeToDisk: true
}
With webpack-dev-server v4.0.0+, devMiddleware is used:
devServer: {
devMiddleware: {
writeToDisk: true
}
}
webpack-dev-server uses a "virtual" Express server in conjunction with Sock.js to emulate a server running on your machine. Regarding compilation, webpack-dev-server does recompile the bundle whenever it detects code changes. This recompilation is served from memory, however, as opposed to the project's build directory (or, in your case, the dist directory). From the docs:
Using this configuration, webpack-dev-server will serve the static files in your build folder. It’ll watch your source files, and recompile the bundle whenever they are changed.
Regarding writing to your disk, webpack-dev-server does not do this. This is partially addressed by what's been written above. Additionally, note the following, also from the Webpack docs:
This modified bundle is served from memory at the relative path specified in publicPath (see API). It will not be written to your configured output directory. Where a bundle already exists at the same URL path, the bundle in memory takes precedence (by default).
To write to your disk, use the ordinary webpack module. Of course, as your question hints at, manual recompilation after every change is tedious. To address that chore, include the watch flag. From the Terminal, you could execute the command:
$ webpack --watch
I prefer to delegate this to an NPM script, however. Note that the -w flag below is equivalent to writing --watch.
// NPM `scripts` field:
"watch": "webpack -w"
If you want to run webpack-dev-server while also having your changes get recompiled and written to your output directory, you can add an additional NPM script like so:
"scripts": {
"serve": "npm run watch && npm run start",
"start": "webpack-dev-server --progress --colors",
"watch": "webpack -w"
}
Then, in your Terminal, just execute $ npm run serve to accomplish this.
If you're interested in the added convenience of automatic reload, you can do so by defining the following within the plugins field of your Webpack config file:
new webpack.HotModuleReplacementPlugin()
Note: This will likely require additional configuration settings for Babel. If I were you, I would take out the query field from your babel loader and, instead, delegate your Babel configuration to an external .babelrc file. A good one to use that is compatible with hot reloading might look like this:
{
"presets": ["env", "es2015", "react"],
"plugins": ["react-hot-loader/babel"]
}
On a side note, I've created a boilerplate repo for easily starting out projects with my desired structure. The Webpack configuration may of interest to, specifically. In particular, it employs Webpack 2 and includes other build tools like Babel (for transpilation), ESLint (syntax checker) as well as support for CSS/Sass and a variety of other file formats.
You can change your start script definition to this:
"start": "webpack --watch & webpack-dev-server --inline --progress --colors".
This sends the webpack watch-and-rebuild process to the background so that you can also hot-reload your modified modules as you change them with webpack-dev-server.
EDIT:
Either of these plugins may do what you want:
https://github.com/gajus/write-file-webpack-plugin
https://github.com/FormidableLabs/webpack-disk-plugin
webpack-dev-server serve files from memory, you can replace webpack-dev-server with webpack-simple-serve, it use webpack's watch feature, write the compiled files to disk and use serve-handler to serve.

Trouble implementing Webpack css-loader, error on compile

I'm new to webpack, and I'm playing around with trying to create my own build from forking another decent build.
One of things that wasn't compiling was the css, so I did the following:
Make sure there were no css loaders currently in the webpack config file (there weren't)
Run npm install css-loader --save-dev
Add loaders
Add import css from './static/css/style.css'; to my entry .js file
Make some arbitrary changes to my css to test
Just for the sake of clarity, my loaders looked like this:
loaders: [
{ ...babel loader... },
{ test: /\.css$/, loader: "style-loader!css-loader" },
{ test: /\.png$/, loader: "url-loader?limit=100000" },
{ test: /\.jpg$/, loader: "file-loader" }
]
I then ran npm run build, and it was here that my terminal came up with the following error:
ERROR in ./src/app-client.js
Module not found: Error: Cannot resolve module 'style-loader' in /path/to/app/.../src
# ./src/app-client.js 15:13-46
I'm not really sure where I'm going wrong here, any help or pointers would be appreciated.
You probably forgot to install style-loader. So just run:
npm install style-loader --save-dev

Babel not compiling ES6 to ES5 Javascript [duplicate]

I have this code:
"use strict";
import browserSync from "browser-sync";
import httpProxy from "http-proxy";
let proxy = httpProxy.createProxyServer({});
and I have installed babel-core and babel-cli globally via npm. The point is when I try to compile with this on my terminal:
babel proxy.js --out-file proxified.js
The output file gets copied instead of compiled (I mean, it's the same as the source file).
What am I missing here?
Babel is a transformation framework. Pre-6.x, it enabled certain transformations by default, but with the increased usage of Node versions which natively support many ES6 features, it has become much more important that things be configurable. By default, Babel 6.x does not perform any transformations. You need to tell it what transformations to run:
npm install babel-preset-env
and run
babel --presets env proxy.js --out-file proxified.js
or create a .babelrc file containing
{
"presets": [
"env"
]
}
and run it just like you were before.
env in this case is a preset which basically says to compile all standard ES* behavior to ES5. If you are using Node versions that support some ES6, you may want to consider doing
{
"presets": [
["env", { "targets": { "node": "true" } }],
]
}
to tell the preset to only process things that are not supported by your Node version. You can also include browser versions in your targets if you need browser support.
Most of these answers are obsolete. #babel/preset-env and "#babel/preset-react are what you need (as of July 2019).
I had the same problem with a different cause:
The code I was trying to load was not under the package directory, and Babel does not default to transpiling outside the package directory.
I solved it by moving the imported code, but perhaps I could have also used some inclusion statement in the Babel configuration.
First ensure you have the following node modules:
npm i -D webpack babel-core babel-preset-es2015 babel-preset-stage-2 babel-loader
Next, add this to your Webpack config file (webpack.config.js) :
// webpack.config.js
...
module : {
loaders : [
{
test : /\.js$/,
loader : 'babel',
exclude : /node_modules/,
options : {
presets : [ 'es2015', 'stage-2' ] // stage-2 if required
}
}
]
}
...
References:
https://gist.github.com/Couto/6c6164c24ae031bff935
https://github.com/babel/babel-loader/issues/214
Good Luck!
As of 2020, Jan:
STEP 1: Install the Babel presets:
yarn add -D #babel/preset-env #babel/preset-react
STEP 2: Create a file: babelrc.js and add the presets:
module.exports = {
// ...
presets: ["#babel/preset-env", "#babel/preset-react"],
// ...
}
STEP 3:- Install the babel-loader:
yarn add -D babel-loader
STEP 4:- Add the loader config in your webpack.config.js:
{
//...
module: [
rules: [
test: /\.(js|mjs|jsx|ts|tsx)$/,
loader: require.resolve('babel-loader')
]
]
//...
}
Good Luck...
npm install --save-dev babel-preset-node5
npm install --save-dev babel-preset-react
...and then creating a .babelrc with the presets:
{
"presets": [
"node5",
"react"
]
}
...resolved a very similar issue for me, with babel 3.8.6, and node v5.10.1
https://www.npmjs.com/package/babel-preset-node5
https://www.npmjs.com/package/babel-preset-react
Same error, different cause:
Transpiling had worked before and then suddenly stopped working, with files simply being copied as is.
Turns out I opened the .babelrc at some point and Windows decided to append .txt to the filename. Now that .babelrc.txt wasn't recognized by babel. Removing the .txt suffix fixed that.
fix your .babelrc
{
"presets": [
"react",
"ES2015"
]
}
In year 2018:
Install following packages if you haven't yet:
npm install babel-loader babel-preset-react
webpack.config.js
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['es2015','react'] // <--- !`react` must be part of presets!
}
}
],
}
Ultimate solution
I wasted 3 days on this
import react from 'react' unexpected identifier
I tried modifying webpack.config.js and package.json files, and adding .babelrc, installing & updating packages via npm, I've visited many, many pages but nothing has worked.
What worked? Two words: npm start. That's right.
run the
npm start
command in the terminal to launch a local server
...
(mind that it might not work straight away but perhaps only after you do some work on npm because before trying this out I had deleted all the changes in those files and it worked, so after you're really done, treat it as your last resort)
I found that info on this neat page. It's in Polish but feel free to use Google translate on it.

Categories