Building styling in an Azure DevOps extension - reactjs

My extension does not contain any css files when I build it and I don't know what makes it do that. I did not change the Common.tsx that was scaffolded. Neither my own styles or the Azure DevOps UI styling gets packaged or used by components.
Azure DevOps UI documentation says to do this:
https://developer.microsoft.com/en-us/azure-devops/develop/extensions
When consuming the 2.164.0 version or later of the azure-devops-ui package, extensions should import the Azure DevOps global styles in order to get the same look and feel (font family, font sizes, hyperlink treatment, etc.) of Azure DevOps pages. This can be done with the following import:
import "azure-devops-ui/Core/override.css";
This is already done in the Common.tsx by default however.
directory structure
src
│ Common.scss
│ Common.tsx
│
└───Components
└───RESTRequestButton
RESTRequestButton.html
RESTRequestButton.json
RESTRequestButton.scss
RESTRequestButton.tsx
webpack.config.js
const path = require("path");
const fs = require("fs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const entries = {};
const ComponentsDir = path.join(__dirname, "src/Components");
fs.readdirSync(ComponentsDir).filter(dir => {
if (fs.statSync(path.join(ComponentsDir, dir)).isDirectory()) {
entries[dir] = "./" + path.relative(process.cwd(), path.join(ComponentsDir, dir, dir));
}
});
module.exports = {
entry: entries,
output: {
filename: "[name]/[name].js"
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {
"azure-devops-extension-sdk": path.resolve("node_modules/azure-devops-extension-sdk")
},
},
stats: {
warnings: false
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.s[ac]ss?$/,
use: ["style-loader", "css-loader", "azure-devops-ui/buildScripts/css-variables-loader", "sass-loader"]
},
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.woff?$/,
use: [{
loader: 'base64-inline-loader'
}]
},
{
test: /\.html?$/,
loader: "file-loader"
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: "**/*.html", context: "src/Components" }
]
})
]
};
Common.tsx
import "azure-devops-ui/Core/override.css";
import "es6-promise/auto";
import * as React from "react";
import * as ReactDOM from "react-dom";
import "./Common.scss";
export function showRootComponent(component: React.ReactElement<any>) {
ReactDOM.render(component, document.getElementById("root"));
}
RESTRequestButton.scss
#import "node_modules/azure-devops-ui/Core/_platformCommon.scss";
RESTRequestButton.tsx (only how I import the styling and how I reference Common.tsx)
import "./RestRequestButton.scss";
import { showRootComponent } from "../../Common";
class RESTRequestButton extends React.Component<{}, {}> {
//a lot of code goes here
}
export default RESTRequestButton;
showRootComponent(<RESTRequestButton />);

The solution was to bump package versions. I set package style-loader to "^3.3.1" and it was fixed.

Related

Self Hosted Font in material-ui theme component library not working

I'm building a component library to sit alongside some react apps within a monorepo, library is currently being consumed by app1 and displaying components exported from the library just fine.
The library is based on masterial ui and themed. I'm using storybook and rollup for documentation and bundling, which means having to cater to both webpack (for storybook) and rollup for the actual library build.
.storybook/main.js:
module.exports = {
stories: ['../src/**/**/*.stories.mdx', '../src/**/**/*.stories.tsx'],
addons: [
'#storybook/addon-links',
'#storybook/addon-essentials',
'storybook-addon-designs'
],
webpackFinal: (config) => {
// Default rule for images /\.(svg|ico|jpg|jpeg|png|gif|eot|otf|webp|ttf|woff|woff2|cur|ani|pdf)(\?.*)?$/
const fileLoaderRule = config.module.rules.find(
(rule) => rule.test && rule.test.test('.svg')
)
fileLoaderRule.exclude = /\.svg$/
config.module.rules.push(
{
test: /\.svg$/,
enforce: 'pre',
loader: require.resolve('#svgr/webpack')
},
{
test: /\.(woff|woff2|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: require.resolve('file-loader'),
options: {
// Limit at 50k. Above that it emits separate files
limit: 50000,
// Output below fonts directory
name: '[name].[ext]',
outputPath: '../src/build/fonts/'
}
}
]
}
)
return config
}
}
And my rollup.config.js:
import commonjs from '#rollup/plugin-commonjs'
import resolve from '#rollup/plugin-node-resolve'
import peerDepsExternal from 'rollup-plugin-peer-deps-external'
import typescript from 'rollup-plugin-typescript2'
import svgImport from 'rollup-plugin-svg-hyperscript'
import url from '#rollup/plugin-url'
import packageJson from './package.json'
export default {
input: './src/index.ts',
output: [
{
file: packageJson.main,
format: 'cjs',
sourcemap: true
},
{
file: packageJson.module,
format: 'esm',
sourcemap: true
}
],
plugins: [
peerDepsExternal(),
resolve(),
commonjs(),
typescript(),
svgImport(),
url({
include: ['**/*.woff', '**/*.eot'],
name: '[name].[ext]'
})
]
}
It should be noted that I have an Icon component that works with SVGS being bundled with rollup and displaying in storybook perfectly.
Font index:
import soehneWebKraftigWoff from './soehneWebKraftig.woff'
import soehneWebKraftigEot from './soehneWebKraftig.eot'
import soehneWebLeichtWoff from './soehneWebLeicht.woff'
import soehneWebLeichtEot from './soehneWebLeicht.eot'
export const fonts = {
soehneWebKraftigWoff,
soehneWebKraftigEot,
soehneWebLeichtEot,
soehneWebLeichtWoff
}
MuiCssBaseline:
import { fonts } from '../../fonts'
export const soehneWebKraftig = {
fontFamily: 'SoehneWebKraftig',
fontStyle: 'normal',
fontWeight: 400,
src: `url(${fonts.soehneWebKraftigWoff}) format('woff')`
}
export const MuiCssBaseline = {
'#global': {
'#font-face': [soehneWebKraftig]
}
}
The override is being indexed and exported from a folder called 'overrides' so this is my theme file:
import { createTheme } from '../../themeUtility'
import { rootPalette } from './rootPalette'
import { rootTypography } from './rootTypography'
import * as overrides from './overrides'
export const rootTheme = createTheme({
palette: rootPalette,
typography: rootTypography,
overrides: {
...overrides
}
})
The font is not loaded correctly in either storybook or in the rollup bundle (I can't see the font displaying correctly in app1 which consumes the bundle). I can see my font files renamed with hashes appearing in the rollup build output directory.
Any ideas?
Edit:
Fonts within build (but not inside the fonts folder?)

Module not found: Error: Can't resolve './component/Hello'

I´m trying to import a simple Component but the webpack seems to cant find it. The route is good and the "resolve" in the webpack config is great too, therefore I cant understand where is the issue.
Give it at look please.
By the way, its a Sails/React environment.
ERROR in ./assets/src/component/Hello.jsx 6:12
Module parse failed: Unexpected token (6:12)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file.
Hello.jsx:
import React from 'react'
class Hello extends React.Component {
render() {
return(
<div> // Err supposed to be here (line6)
Hello World!
</div>
)
}
}
export default Hello;
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './component/Hello'
const App = () => {
return (
<div>
Simple Sails-React stater
<Hello/>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
.babelrc:
{
"presets": ["#babel/env", "#babel/react"]
}
webpack config file:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
entry: './assets/src/index.js'
},
output: {
path: __dirname + '/.tmp/public',
filename: 'bundle.js'
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
use: ['style-loader', 'css-loader'],
test: /\.css$/
}
]
},
resolve: {
extensions: ['*', '.js', '.jsx']
},
plugins: [
new HtmlWebpackPlugin({
template: 'assets/src/index.html'
})
]
};
the structure is like this:
-src
--component
----Hello.jsx
--index.js
--index.html
Could you try change extension to Hello.js or change bable-loader test to
test: /\.(js|jsx)$/,

Ant Design components style not loading correctly

Recently I decided to build my own setup for react & webpack
So I faced some problems with UI libraries like antd or Bulma when import component like button the style of it doesn't work
this is my index.js
import React from 'react';
import ReactDom from 'react-dom';
import 'antd/dist/antd.css';
import { Button } from 'antd';
import './index.css';
const Index = () => (
<div>
<Button type="primary">Primary</Button>
</div>
)
;
ReactDom.render(<Index/>,document.getElementById('root'));
and this is my output
(I uploaded the image on imgur because I'm not allowed to upload images on StackOverflow until I got 10 reputations)
this is my webpack setting code
const path= require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports={
entry:path.resolve(__dirname,'src/index.js'),
output: {
path: path.resolve(__dirname,'dist'),
filename: "bundle.js"
},
module: {
rules: [
{
test:/\.js$/,
use:"babel-loader",
exclude:/node_modules/,
},
{
test:/\.(css|scss)$/,
use:[
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true,
modules: true,
camelCase: true,
localIdentName: '[local]___[hash:base64:5]',
},
},
'sass-loader',
]
},
{
test:/\.less/,
use:[
"less-loader",
]
},
{
test: /\.(gif|png|jpe?g|svg)$/i,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
bypassOnDebug: true,
disable: true
}
}
]
},
{
test:/\.(jpg|png|gif)$/i,
exclude:/node_modules/,
use:{
loader: "url-loader",
options:{
limit:8000
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'src/index.html')
})
]
};
I ran into a similar issue, here's how I managed to solve it;
Replace your webpack rule for less files with this:
{
test: /\.less$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "less-loader", options: { javascriptEnabled: true } }
]
}
NB: You should have style-loader, css-loader and less-loader installed.
Import antd.less instead of antd.css
In your index.js file, use import "antd/dist/antd.less" instead of import "antd/dist/antd.css" ensure you have less installed too.
Hope this helps!!

Webpack 4: Module parse failed: Unexpected token

During my builds, webpack is giving me this error:
ERROR in ./client/components/App/index.tsx 15:9
Module parse failed: Unexpected token (15:9)
You may need an appropriate loader to handle this file type.
|
|
> const App: SFC = () => (
| <div style={{ background: "red" }}>
| <h3>test</h3>
# ./client/index.tsx 11:4-14:6 12:24-51
# multi react-hot-loader/patch ./client/index.tsx webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true
Here is my webpack.config.ts:
import CleanWebpackPlugin from "clean-webpack-plugin";
import HtmlWebpackPlugin from "html-webpack-plugin";
import path from "path";
import { Configuration, HotModuleReplacementPlugin } from "webpack";
const rootDir = ["..", "..", "..", ".."];
const distDir = ["..", ".."];
// this file lives in one place as `.ts` and another as `.js` grab the
// file extension to determine the include path relative to its location
const include =
path.extname(module.id) === ".ts"
? path.resolve(__dirname, "client", "index.tsx")
: path.resolve(__dirname, ...rootDir, "client", "index.tsx");
const exclude = /node_modules/;
const tsconfig = path.resolve(
__dirname,
...rootDir,
"config",
"tsconfig.client.json"
);
// development plugins
const plugins = [
new HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "..", "..", "..", "index.html")
}),
new CleanWebpackPlugin([path.resolve(__dirname, ...distDir, "*.*")], {
allowExternal: true,
root: __dirname,
verbose: true
})
];
// script for webpack-hot-middleware
const hotMiddlewareScript: string =
"webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true";
const webpackDevConfig: Configuration = {
context: path.resolve(__dirname, ...rootDir),
devtool: "source-map",
entry: {
app: ["react-hot-loader/patch", include, hotMiddlewareScript]
},
mode: "development",
module: {
rules: [
{
exclude,
include,
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
exclude,
include,
loader: "ts-loader",
options: {
configFile: tsconfig,
transpileOnly: true
},
test: /\.tsx?$/
},
{
enforce: "pre",
exclude,
include,
loader: "source-map-loader",
test: /\.js$/
}
]
},
optimization: {
nodeEnv: "development"
},
output: {
filename: "[name].bundle.js",
path: path.join(__dirname, ...distDir),
publicPath: path.join(__dirname, ...distDir, "static/")
},
plugins,
resolve: {
extensions: [".js", ".ts", ".tsx", "*"]
},
target: "web"
};
export default webpackDevConfig;
My App.tsx:
import React, { SFC } from "react";
import ReactDOM from "react-dom";
const App: SFC = () => (
<div style={{ background: "red" }}>
<h3>test</h3>
</div>
);
My index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./components";
ReactDOM.render(<App />, document.getElementById("app"));
// enables Hot Module Replacement (HMR)
if ((module as any).hot) {
(module as any).hot.accept("./components/App", () => {
// for HMR to work, `App` must be re-required
const NextApp = require("./components/App").default;
ReactDOM.render(<NextApp />, document.getElementById("app"));
});
}
My tsconfig.json:
{
"compilerOptions": {
"allowJs": true,
"jsx": "react",
"module": "commonjs",
...
}
}
The error itself seems to give the solution: You may need an appropriate loader to handle this file type., however, it is my understanding that ts-loader should be able to handle react.
Here is an example webpack.config provided by the ts-loader team used in an app that uses typescript and react. The set up is fairly similar to my own, however, I do not use webpack-dev-server, rather, I use webpack-dev-middleware.
The issue was resolved by niba's comment on the original question. It seems that ts-loader when given a single module to include will not traverse the linked modules. Removing the include field or using the folder name fixed this error for me.

How to use CSS Modules with webpack in React isomorphic app?

I am build an isomorphic app using react, react-router, express and webpack. Now I want to use css modules to import css.
I use import './index.css' in index.jsx, it works fine on client, but doesn't work on server rendering. The error is Error: Cannot find module './index.css'.
components/index.jsx
import React, {Component, PropTypes} from 'react';
import style from './index.css';
class App extends Component {
constructor(props, context) {
super(props, context);
}
render() {
return (
<div id="login">
// ...
</div>
);
}
};
export default App;
server/router/index.js
import url from 'url';
import express from 'express';
import swig from 'swig';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {match, RouterContext} from 'react-router';
import routes from '../../client/routes/routes';
import DataWrapper from '../../client/container/DataWrapper';
import data from '../module/data';
const router = express.Router();
router.get('*', async(req, res) => {
match({
routes,
location: req.url
}, async(error, redirectLocation, props) => {
if (error) {
res.status(500).send(error.message);
} else if (redirectLocation) {
res.status(302).redirect(redirectLocation.pathname + redirectLocation.search);
} else if (props) {
let content = renderToString(
<DataWrapper data={data}><RouterContext {...props}/></DataWrapper>
);
let html = swig.renderFile('views/index.html', {
content,
env: process.env.NODE_ENV
});
res.status(200).send(html);
} else {
res.status(404).send('Not found');
}
});
});
export default router;
webpack.config.dev.js(for webpack-dev-server)
var webpack = require('webpack');
var config = require('./config');
module.exports = {
devtool: 'inline-source-map',
entry: [
'webpack-dev-server/client?http://localhost:' + config.webpackPort,
'webpack/hot/only-dev-server',
'./src/client/entry',
],
output: {
path: __dirname + '/public/js',
filename: 'app.js',
publicPath: 'http://localhost:' + config.webpackPort + '/public/js',
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify('development')
}
})
],
resolve: {
extensions: ['', '.js', '.jsx', '.css']
},
module: {
loaders: [{
test: /\.jsx?$/,
loader: 'react-hot',
exclude: /node_modules/
}, {
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.css$/,
loader: 'style-loader!css-loader?modules',
exclude: /node_modules/
}, {
test: /\.(png|woff|woff2|svg|ttf|eot)$/,
loader: 'url-loader',
exclude: /node_modules/
}]
}
}
I'd recommend using webpack to compile UI code for both client and server side in that case. Just set target: "node" in webpack config to produce bundle which can executed in Node environment.
That article might help for compiling your server side code with Webpack: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Especially on how to exclude node_modules with the externals key.
A very bare config might look like:
'use strict';
const path = require('path');
const fs = require('fs');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const rootDir = path.resolve(__dirname, '..');
const distDir = path.join(rootDir, 'dist');
const srcDir = path.join(rootDir, 'src');
const localStyles = new ExtractTextPlugin('local.css', { allChunks: true });
const nodeModules = fs.readdirSync('node_modules')
.filter(dir => !dir.startsWith('.'))
.reduce((acc, prop) => {
acc[prop] = 'commonjs ' + prop;
return acc;
}, {});
const loaders = [
{
test: /\.(js|jsx)$/,
include: srcDir,
exclude: /node_modules/,
loader: 'babel',
query: {
cacheDirectory: true,
},
},
{
test: /\.css$/,
include: srcDir,
loader: localStyles.extract(
'style',
'css?modules&localIdentName=[name]-[local]_[hash:base64:5]'
),
},
{
test: /\.json$/,
loader: 'json',
},
];
module.exports = {
target: 'node',
entry: {
server: ['server/index'],
},
output: {
path: distDir,
filename: '[name].bundle.js',
},
externals: nodeModules,
module: {
loaders,
},
plugins: [
localStyles,
],
};
Another solution (Webpack free) could be to use babel-plugin-css-modules-transform
.

Resources