DOCS:
https://material-ui.com/guides/minimizing-bundle-size/#development-environment
"Create a .babelrc.js file in the root directory of your project:
const plugins = [
[
'babel-plugin-transform-imports',
{
'#material-ui/core': {
// Use "transform: '#material-ui/core/${member}'," if your bundler does not support ES modules
'transform': '#material-ui/core/esm/${member}',
'preventFullImport': true
},
'#material-ui/icons': {
// Use "transform: '#material-ui/icons/${member}'," if your bundler does not support ES modules
'transform': '#material-ui/icons/esm/${member}',
'preventFullImport': true
}
}
]
];
module.exports = {plugins};"
https://nextjs.org/docs/advanced-features/customizing-babel-config
"To add presets/plugins with custom configuration, do it on the next/babel preset like so:
{
"presets": [
[
"next/babel",
{
"preset-env": {},
"transform-runtime": {},
"styled-jsx": {},
"class-properties": {}
}
]
],
"plugins": []
}"
QUESTION:
How to properly configure babel for material-ui in Next.js ? My implementation below is apparently incorrect as import { ConstructionOutlined } from '#material-ui/icons';is still causing very long load times in dev mode. I observed no error messages when trying the below implementation and variations.
CODE:
{
"presets": [
[
"next/babel",
{
"babel-plugin-transform-imports":
{
"#material-ui/core": {
// Use "transform: '#material-ui/core/${member}'," if your bundler does not support ES modules
"transform": "#material-ui/core/esm/${member}",
"preventFullImport": true
},
"#material-ui/icons": {
// Use "transform: '#material-ui/icons/${member}'," if your bundler does not support ES modules
"transform": "#material-ui/icons/esm/${member}",
"preventFullImport": true
}
}
}
]
],
"plugins": []
}
OR
module.exports = {
presets: [
["next/babel"]
],
plugins: [
[
'babel-plugin-import',
{
'libraryName': '#material-ui/core',
// Use "'libraryDirectory': ''," if your bundler does not support ES modules
'libraryDirectory': 'esm',
'camel2DashComponentName': false
},
'core'
],
[
'babel-plugin-import',
{
'libraryName': '#material-ui/icons',
// Use "'libraryDirectory': ''," if your bundler does not support ES modules
'libraryDirectory': 'esm',
'camel2DashComponentName': false
},
'icons'
],
]
}
OR ELSE ?
I could exactly understand your problem. Follow this.
npm install babel-plugin-import --save-dev
Create a .babelrc file in the root directory of your next.js project with the following content:
{
"presets": ["next/babel"],
"plugins": [
[
'babel-plugin-import',
{
libraryName: '#mui/material',
libraryDirectory: '',
camel2DashComponentName: false,
},
'core',
],
[
'babel-plugin-import',
{
libraryName: '#mui/icons-material',
libraryDirectory: '',
camel2DashComponentName: false,
},
'icons',
],
]
}
Restart your development server.
This above babel configuration will convert
// from
import { Button, TextField } from '#mui/material'; ( great developer experience)
// to
import Button from '#mui/material/Button'; (smaller bundle size means great user experience)
import TextField from '#mui/material/TextField';
As a result, you will notice
faster loading of development server.
smaller bundle size
also faster client navigation with next/link and fallback:true.
Source: Babel config docs
Mui
Next.js
Hope it works for you too!
Adding babel-plugin-transform-imports is what worked for me. My .babelrc file looks like this:
{
"presets": ["next/babel"],
"plugins": [
[
"babel-plugin-transform-imports",
{
"#material-ui/core": {
"transform": "#material-ui/core/${member}",
"preventFullImport": true
},
"#material-ui/icons": {
"transform": "#material-ui/icons/${member}",
"preventFullImport": true
}
}
]
]
}
Try using the non-esm version that you have commented out in your implementation. After doing that the build time dropped significantly for me. I did have to update styles imports for Material UI like they recommend in their documentation as well.
Related
I have a React component library that is built by webpack 5.75.0. The library exports 2 components:
// src/index.ts
export { default as ComponentA } from "components/ComponentA";
export { default as ComponentB } from "components/ComponentB";
A simple CRA app uses this library and imports only ComponentA. But when analyzing the bundle I see that ComponentB's dependencies are in it and have not been tree-shaken.
The parent app is just a CRA app with no config overrides. Tree shaking works there for other modules (MUI, lodash-es, etc), so the problem is with the my library.
I seem to have followed all requirements: in my package.json I do have
"sideEffects": false,
"main": "lib/index.js",
"module": "lib/index.js",
Here's my babel config:
module.exports = {
presets: [
["#babel/preset-env", { targets: { node: "current", modules: false } }],
"#babel/preset-typescript",
[
"#babel/preset-react",
{
runtime: "automatic",
},
],
],
plugins: [
"#babel/plugin-syntax-jsx",
[
"#babel/plugin-transform-runtime",
{
regenerator: true,
useESModules: true,
},
],
],
};
And here's my webpack config:
const config = {
mode: "production",
devtool: false,
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "lib"),
filename: "index.js",
module: true,
library: {
type: "module",
},
},
plugins: [
//...
],
module: {
rules: [
//...
],
},
resolve: {
//...
},
externals: [
"react",
"react-dom",
],
experiments: {
outputModule: true,
},
optimization: {
minimize: false,
},
};
But still, the ComponentB's dependencies are showing up in the bundle of the CRA app that uses this library.
Am I missing something? Is there some official example of how to configure tree-shaking library with webpack 5?
Thanks.
P.S. My question relates to this question, but since 2021 it's become possible to build ES modules with Webpack 5.
I use rollup to create multiple libs, rollup config file as below:
import terser from '#rollup/plugin-terser';
import { nodeResolve } from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import { babel } from '#rollup/plugin-babel';
import eslint from '#rollup/plugin-eslint';
const distDir = "dist/libs"
const api = {
input: "src/libs/api/index.js",
external: ["axios"],
output: [
{
file: `${distDir}/api.umd.js`,
format: "umd",
name: 'Api',
globals: {axios: 'axios'}
},
{
file: `${distDir}/api.es.js`,
format: "es"
}
],
plugins: [
terser(),
babel({babelHelpers: 'runtime', exclude: 'node_modules/**'}),
nodeResolve({
browser:true,
}),
commonjs(),
eslint({
throwOnError: true,
throwOnWarning: true,
include: ['src/**'],
exclude: ['node_modules/**']
})
]
}
const test = {
...
}
export default ()=>{
return [
api, // it contains some polyfill
test // it also contains some polyfill
]
};
My .babelrc is:
{
"presets": [
["#babel/preset-env", {
"corejs": {"version": "3", "proposals": false},
"useBuiltIns": "usage"
}
]
],
"plugins": [
[
"#babel/plugin-transform-runtime"
]
]
}
Now, api and test contain some polyfill. Is there a way to extract the used polyfills of all modules to form a single umd file but not Full Function polyfill.Thank you.
I'm trying to release a library that contains Flow syntax in several forms, using Rollup and Babel:
UMD, ES5 (works)
UMD, ES5, minified (works)
ES module (problem)
Specifically, I want the ES module version to be as minimally transpiled as possible: it should use the full range of ES6 features just as I wrote them. I can't seem to stop Babel transpiling down to ES5 though - it creates an _objectSpread2() function and replaces every spread operator with it.
The only reason I want to use Babel is for the Flow syntax. Specifically, converting class property syntax:
class Foo {
myProp = 1;
}
(The standalone tool flow-remove-types does not transform class syntax, so its output is not valid JS).
This is the Rollup config that currently over-transpiles, to ES5:
import { nodeResolve } from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import flow from 'rollup-plugin-flow';
export default [
{
input: 'src/index.js',
output: [
{
file: 'dist/index.esm.js',
format: 'esm', // ES2015 modules version so consumers can tree-shake
},
],
plugins: [flow(), commonjs(), nodeResolve()],
},
];
Even when I remove the presets, it still does exactly the same thing:
import babel from '#rollup/plugin-babel';
export default [
{
input: 'src/index.js',
output: [
{
file: 'dist/index.esm.js',
format: 'esm', // ES2015 modules version so consumers can tree-shake
},
],
plugins: [
babel({
presets: [],
}),
],
},
];
Do I need to change something in .babelrc? It is currently as follows:
{
"presets": [
[
"#babel/preset-env",
{
"targets": {
"esmodules": true
}
}
],
["#babel/preset-flow"]
]
}
The library is here.
Hmm, I think the problem was that .babelrc was being applied even in the ESM case. So the answer is:
Remove the .babelrc file
Move its configuration to rollup.config.js
Configure rollup-esm.config.js to explicitly handle class syntax.
Rollup.config.js:
...
plugins: [
flow(),
commonjs(),
nodeResolve(),
babel({
babelHelpers: 'bundled',
presets: [
[
'#babel/preset-env',
{
targets: {
esmodules: true,
},
},
],
['#babel/preset-flow'],
],
}),
],
rollup-esm.config.js:
import babel from '#rollup/plugin-babel';
export default [
{
input: 'src/index.js',
output: [
{
file: 'dist/index.esm.js',
format: 'esm', // ES2015 modules version so consumers can tree-shake
},
],
plugins: [
babel({
plugins: ['#babel/plugin-proposal-class-properties'],
presets: ['#babel/preset-flow'],
}),
],
},
];
How can I export my component's propTypes so when I include this package in my project, IDE can suggest them without affecting my bundle size ?
Or how the user may be able to get rid of them ?
Is it safe to mark prop-types as peeDependency since react includes it ?
I use rollup#1.27.13 and #babel/core#7.7.7 and few other plugins for each of them.
When I remove propTypes using the code bellow, my bundle size is 1.58kb gzipped
{
"presets": [
"#babel/preset-react",
["#babel/preset-env", {
"modules": false
}]
],
"plugins": [
["transform-react-remove-prop-types", {
"removeImport": true
}],
"#babel/plugin-proposal-optional-chaining"
]
}
But when I leave them (and then I can get suggestions by IDE) it jumps to 6.45kb gzipped.
rollup config:
{
input: 'src/index.js',
output: [
{
file: pkg.main,
format: 'cjs'
},
{
file: pkg.module,
format: 'es'
}
],
plugins: [
external(),
babel({
exclude: 'node_modules/**'
}),
resolve(),
commonjs(),
terser()
],
}
Thanks
I am currently trying to convert our existing vue.js project into nuxt.js. I am unable to add flowtype support in nuxt.js. when i run the flow server it says no errors!! but running npm run dev, its throwing error on the flow syntax.
.flowconfig
[include]
pages/**/.*
components/**/.*
layouts/**/.*
apiRoutes/.*
store/.*
utils/.*
[ignore]
.*/build/.*
.*/config/.*
.*/dist/.*
.*/node_modules/.*
.*/static/.*
.*/test/.*
.*/ssl/.*
.*/.nuxt/.*
[libs]
./flow/
[options]
emoji=true
module.file_ext=.vue
module.file_ext=.js
server.max_workers=3
log.file=./flow.log
suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe
unsafe.enable_getters_and_setters=true
module.system.node.resolve_dirname=node_modules
module.name_mapper='^.*\.css$' -> 'empty/object'
module.name_mapper='^.*\.js$' -> 'empty/object'
module.name_mapper='^#/\(.*\)$' -> '<PROJECT_ROOT>/\1'
i've added all the neccessary babel and eslint packages.
.babelrc
{
"presets": [
["env", { "modules": false }],
"stage-2",
["es2015", {"modules": false }],
"flow-vue"
],
"plugins": [
"transform-runtime",
"transform-class-properties",
"syntax-flow",
"transform-flow-strip-types"
],
"comments": false,
"env": {
"test": {
"presets": ["env", "stage-2"],
"plugins": [ "istanbul" ]
}
}
}
.eslintrc.js
module.exports = {
root: true,
parserOptions: {
parser: 'babel-eslint',
sourceType: 'module'
},
env: {
browser: true,
node: true,
jquery: true
},
extends: [
'standard',
'plugin:flowtype/recommended'
// 'plugin:vue/recommended'
],
// required to lint *.vue files
plugins: [
'html',
'flowtype-errors',
'flowtype'
],
// add your custom rules here
rules: {
'flowtype-errors/show-errors': 2,
// allow paren-less arrow functions
'arrow-parens': 0,
'semi': ["error", "always"],
// allow async-await
'generator-star-spacing': 0
},
globals: {}
}
On running npm run dev, it doesnt parse flowtype syntax
I suggest following the instructions on the flow website to set up Babel. In particular there is a preset, so you shouldn't need to configure individual rules. Then you'll actually need to run Babel (again, instructions are on the website). Once you have run Babel, you should be able to run the code it outputs in Node.