webpack separate build files - reactjs

I have a nested directory structure with jsx modules, like
app/js/header/index.jsx
app/js/task/runner.jsx
and so on
is it possible to have webpack transpile each one of them and output the result in the same directory as the jsx file?
Regards

If I understand you correctly, you want to put resulting module next to each source module. It seems that you can achieve this with a plugin:
var fs = require('fs');
function MyPlugin() {}
MyPlugin.prototype.apply = function(compiler) {
compiler.plugin('emit', function(compilation, callback) {
compilation.modules.forEach(m => {
if (/filename/.test(m.resource)) { // test for filename to exclude node_modules
fs.writeFileSync(m.resource + '.transpiled', m._source._value);
}
});
callback();
});
};
and in the webpack config:
{
...
plugins: [ MyPlugin() ],
...
}
Is it what you are trying to do?

Related

How to add typescript paths to storybook

I have a react application with a custom Webpack configuration.
After adding Webpack aliases that matches tsconfig.json file compilerOptions->paths field the aliases were recognized by webpack.
Since storybook comes with a built in Webpack configuration, my aliases are not read by Storybook and I'm getting the following error:
Module not found: Error: Can't resolve <path with typescript alias> in <some folder path>
In Storybook main.js file, add the following:
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
...,
webpackFinal: async (config, { configType }) => {
config.resolve.plugins = [new TsconfigPathsPlugin()];<-- this line
return config;
}
};
You can install tsconfig-paths-webpack-plugin using the following command from the folder in which your application's package.json file resides:
npm i tsconfig-paths-webpack-plugin -D
Solution was derived from this discussion:
https://github.com/storybookjs/storybook/issues/6316
For future vistors of this question, since 15th July of 2022 storybooks can use Vite instead Webpack.
In that case I recommend using vite-tsconfig-paths instead of tsconfig-paths-webpack-plugin. If you are using TS paths in Vite, you probably already have this package installed.
Add this to your .storybook/main.js
const { mergeConfig } = require("vite")
const { default: tsconfigPaths } = require('vite-tsconfig-paths')
module.exports = {
// your previous configs and more...
viteFinal(config, { configType }) {
return mergeConfig(config, {
plugins: [
tsconfigPaths()
]
})
}
}
An alternative to accepted solution:
If you prefer not to install an external library such as tsconfig-paths-webpack-plugin, you can create a custom file, say:
tsconfig-webpack-utils.js
and do something similar to the following:
const { compilerOptions } = require('../tsconfig.json');
function getAliases() {
const baseUrl = getTSBaseUrl();
return Object.fromEntries(Object.entries(compilerOptions.paths).map(([key, value]) => {
return [
key.replace(/\/\*\*?$/,''),
value.map(entryPath => path.resolve(__dirname, baseUrl, entryPath.replace(/\/\*\*?$/,'/')))
]
}));
}
function getTSBaseUrl() {
return path.resolve(__dirname, `../${compilerOptions.baseUrl}`);
}
exports.addTsDefinitionsToWebpack = function(webpackConfig) {
if (!webpackConfig.resolve.modules) {
webpackConfig.resolve.modules = ['node_modules'];
}
webpackConfig.resolve.modules.push(getTSBaseUrl());
webpackConfig.resolve.alias = {
...webpackConfig.resolve.alias,
...getAliases()
};
}
This solution only works for very simple aliases. It is recommended to use an appropriate library or to expand this solution according to your needs.
You can then use it as follows in every webpack config you require it:
addTsDefinitionsToWebpack(webpackConfig);

Storybook 6, use module paths?

Is it possible to configure storybook 6 to use the module paths in my tsconfig.json file to work with sass-loader (or just to replicate the same pattern if that's not possible).
Ideally, I'd like to be able to add a sass loader with this option:
additionalData: `
#use '#themes' as vars;
#use '#themes/breakpoints' as bp;
`,
instead of
additionalData: `
#use '../themes' as vars;
#use '../themes/breakpoints' as bp;
`,
My tsconfig.json file has this section in it which works well inside .ts files but obviously doesn't work in sass files:
"paths": {
"#components/*": ["./components/*"]
}
If I could replicate that for themes, that'd be amazing.
Turns out it was pretty easy:
in main.js. Add the following to your module.exports:
webpackFinal: async (config, { configType }) => {
config.resolve.alias = {
...config.resolve.alias,
"#themes": path.resolve(__dirname, "../themes/default")
}
return config;
}
Actually, past Alex, there is a better solution now using the ts-config-paths-webpack-plugin that is automatic and doesn't require repeating config code:
// main.js
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const pathsPlugin = new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, '../tsconfig.json')
})
webpackFinal: async (config) => {
if (config.resolve.plugins) {
config.resolve.plugins.push(pathsPlugin);
} else {
config.resolve.plugins = [pathsPlugin];
}
...

How to implement react-dates css in css-modules?

so react-dates css worked fine until i moved to css-modules. i tried importing the css file from node modules in index.js files and in the head of the html file but none of them worked.
Any help or suggestion will be greatly appreciated.
This is working perfectly for this problem
In webpack.config.js define a function which checks your file to
decide if it's css module or global; done using getLocalIdent
option.
This is the method that I'm currently using in my setup.
This also requires your files to have some naming convention,
[name].module.css for css modules and [name].css for regular files.
See example below:
// regex to test for modules, loaderUtils is part of webpack dependencies
const cssModuleRegex = new RegExp(/\.module\.(less|css)$/);
const loaderUtils = require("loader-utils");
// inside webpack rules
{
test: /\.(less|css)$/,
use: [
{
loader: CssExtractPlugin.loader,
options: { hot: is_dev, reloadAll: is_dev }
},
{
loader: "css-loader",
options: {
modules: {
localIdentName: '[local]___[hash:base64:5]',
getLocalIdent: getLocalIdent
}
}
},
"postcss-loader",
"less-loader"
]
}
// this is a copy of the default function, modified slightly to achieve our goal
function getLocalIdent(loaderContext, localIdentName, localName, options) {
// return local name if it's a global css file
if (!cssModuleRegex.test(loaderContext.resourcePath)) {
return localName;
}
if (!options.context) {
// eslint-disable-next-line no-param-reassign
options.context = loaderContext.rootContext;
}
const request = path
.relative(options.context, loaderContext.resourcePath)
.replace(/\\/g, '/');
// eslint-disable-next-line no-param-reassign
options.content = `${options.hashPrefix + request}+${localName}`;
// eslint-disable-next-line no-param-reassign
localIdentName = localIdentName.replace(/\[local\]/gi, localName);
const hash = loaderUtils.interpolateName(
loaderContext,
localIdentName,
options
);
return hash
.replace(new RegExp('[^a-zA-Z0-9\\-_\u00A0-\uFFFF]', 'g'), '-')
.replace(/^((-?[0-9])|--)/, '_$1');
}
Source: How to apply global styles with CSS modules in a react app?

How to use "webpack.DefinePlugin" with React Gatsby and React-Bodymoving?

I am pretty new to React but I want to set
BODYMOVIN_EXPRESSION_SUPPORT in Webpack's Define plugin with Gatsby v1.
I followed the links below but I don't get what exactly I suppose to do...
https://github.com/QubitProducts/react-bodymovin
https://www.gatsbyjs.org/docs/environment-variables/
I made the file named .env.development and put it to src folder. the content in this file is below.
plugins: ([
new webpack.DefinePlugin({
BODYMOVIN_EXPRESSION_SUPPORT: true
})
])
The folder structures is
root--
|
|- public //where the build goes
|
|- src -- //where I develop site
|-components
|-data
|-pages
|-style
|-.env.development
What I noticed is there is a line said
/*global BODYMOVIN_EXPRESSION_SUPPORT*/
in bodymovin library and I think I just need to change that. I could modify in library directly maybe but I don't think that a best way to get around this problem. Does someone know how to set this up right?
Thanks in advance!
EDIT 2019-09-02
To use environment variables from .env files I recommend using dotenv because it's so simple. Here's an example that creates an object of all the variables in the .env file and makes them accessible on the client side (i.e in React) through DefinePlugin.
// gatsby-node.js
var dotenv = require('dotenv');
const env = dotenv.config().parsed;
// Create an object of all the variables in .env file
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
exports.onCreateWebpackConfig = ({ stage, rules, loaders, plugins, actions }) => {
actions.setWebpackConfig({
plugins: [
// Add the environment variables to webpack.DefinePlugin with define().
plugins.define(envKeys)
]
});
};
Here's an example of how I get the application name and version from package.json and using it in my service worker, I'm using Gatsby V2 though. Having the version in the service worker makes caching easier to handle. As you wrote, DefinePlugin is the way to go but it's a bit different when we use it in Gatsby.
We need to import the package.json file and add our custom webpack configuration in gatsby-node.js, with plugins.define() we tell webpack to use DefinePlugin:
const packageJson = require('./package');
exports.onCreateWebpackConfig = ({
plugins,
actions,
}) => {
actions.setWebpackConfig({
plugins: [
plugins.define({
__NAME__: JSON.stringify(packageJson.name),
__VERSION__: JSON.stringify(packageJson.version),
}),
],
})
}
The two defined variables __NAME__ and __VERSION__ are now accessible in my service worker sw.js:
self.addEventListener('install', function (e) {
// eslint-disable-next-line
console.log(__NAME__, __VERSION__);
e.waitUntil(
caches.open(__NAME__ + __VERSION__).then(function(cache) {
return cache.addAll(filesToCache);
})
);
});
Gatsby Reference: https://www.gatsbyjs.org/docs/add-custom-webpack-config/

Exports defaults else path not taken with Jest and ES6

I'm having issues to pass my tests with 100% coverage. Istanbul say that exports defaults Component else path not taken.
Because of that, I see in my generated html of istanbul that my tests are not completely at 100%. Mostly in the Statements and Branches tab.
I'm using:
React: 15.4.0
Jest: 17.0.2
Webpack: 1.12.11
Any idea?
The problem was in the jest configuration, we were using a preprocessor in order to resolve some imports:
In the package json we had this:
"transform": {
"^.+\\.js$": "<rootDir>/cfg/preprocessor.js"
},
This file contained this:
const babelJest = require('babel-jest');
require('babel-register');
const webpackAlias = require('jest-webpack-alias');
module.exports = {
process: function (src, filename) {
if (filename.indexOf('node_modules') === -1) {
src = babelJest.process(src, filename);
src = webpackAlias.process(src, filename);
}
return src;
}
};
We updated to Jest v20 and also use the module resolver from Jest, in our package.json we added:
"moduleDirectories": [
"node_modules",
"src"
],
and removed the transform config from the package.json and the preprocessor.js file.

Resources