The default configuration can be extended via a .febuild
file.
This configuration file is loaded and executed as a JavaScript module.
It is used for all files located in the same directory as the .febuild
file and in the subdirectory tree.
You can add multiple .febuild
whenever you need to run a separate build with other options.
These are the configurations that can be extended:
- general
- output
- optimization
- plugins
- eslint
- babel
- sass
- clientlibs
- stylelint
- resolve
- postcss
- templates
Other webpack options
To override a configuration, add a new entry in the object exported in your .febuild
with the name of the configuration you want to override, which value is an object whith entries that matches the existing options you want to override.
E.g., to override the default Babel configuration with new exclude
paths and plugins, you can do the following in your .febuild
file:
module.exports = {
babel: {
exclude: /node_modules\/(?!swiper|dom7)/,
use: {
options: {
plugins: ['@babel/plugin-proposal-optional-chaining', '@babel/plugin-transform-runtime', '@babel/plugin-proposal-object-rest-spread']
}
}
}
};
Default configuration can be extended by using a function instead of an object, which accepts an argument that is the default configuration.
module.exports = (defaultConfig) => ({
babel: {
use: {
options: {
plugins: ['@babel/plugin-proposal-optional-chaining', ...defaultConfig.babel.use.options]
}
}
}
});
This configuration part is used for basic project setup. You will find an explanation of each key as a comment next to it. Defaults:
module.exports = {
general: {
// Your project name with which ClientLibs category are prefixed
projectKey: "myproj",
// Only the source files with this suffix will be compiled
sourceKey: "source",
// The compiled bundle filename suffix
bundleKey: "bundle",
// The path to the directory with your source files
sourcesPath: "src",
// Path to the dir with the code shared among Scss and JS files
common: "common",
// Paths to ignore when the build looks for files to compile
ignore: ["!(**/target/**)", "!(**/jcr_root/**)", "!(**/common/**)"],
// Destination of the compiled files
destinationPath: "dist",
// Name of the configuration file
extendConfigurations: ".febuild",
// Modules to run with webpack, each being a config file (e.g. eslint.config.js)
modules: [ "eslint", "babel" ],
// The tasks to run when executing `npm run build`
defaultTasks: [ "styles", "webpack", "clientlibs" ],
}
}
Example of overriding the defaultTasks
to exclude the 'clientlibs' task:
module.exports = {
general: {
defaultTasks: ['styles', 'webpack']
}
}
Babel webpack plugin, enabled by default in the option general.modules
.
For more information about the configuration options check babel-loader.
{
babel: {
enforce: 'post',
test: /\.js$/,
exclude: /node_modules\/(?!@nc)/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', { useBuiltIns: 'usage', corejs: 3 }]],
plugins: ['@babel/plugin-transform-runtime', '@babel/plugin-proposal-object-rest-spread']
}
}
}
}
By default @babel/preset-env
will use browserslist
config sources unless either the targets
or ignoreBrowserslistConfig
options are set.
When no browser targets are specified, Babel will assume the oldest browsers possible, which will increase the output code size.
We recommend using a .browserslistrc file to specify the targets.
useBuiltIns: usage
This option configures how Babel handles the polyfills, by adding the specific imports only when the polyfill is used in each file.
What is the advantages over "entry"?
- It allows proper tree-shaking the polyfills
- Reduce the size of the JavaScript file entrypoint
core-js 3 is included by default, and set in the options of @babel/preset-env
to import only the polyfills used in your code.
Hence you don't need to import core-js in your project, or code duplication will happen increasing the size of the output code.
Stylelint is a CSS linter which can also lint Scss files.
Default configuration:
module.exports = {
{
stylelint: {
// Stops the build if a linter error is found
failOnError: true
}
}
}
Please note that you need a Stylelint configuration object to parse CSS-like languages like Scss. We recommend extending a shared configuration like @netcentric/stylelint-config.
You can add your own linter rules in the Stylelint configuration object.
ESLint statically analyzes your code to quickly find problems.
For more information about the configuration options check eslint-loader.
module.exports = {
failOnError: true,
fix: true // deprecated with scss only for css
}
Sass is the default CSS preprocessor supported by the fe-build.
{
sass: {
// Paths where Sass will look for stylesheets (when using @import and @use)
includePaths: [path.join(common, 'styles'), nodeModules],
// The output style of the compiled CSS: "expanded, compressed, nested or compact
outputStyle: isProduction ? 'compressed' : 'expanded'
}
}
PostCSS is used to transform the CSS code generated after the Sass compilation.
Default configuration:
{
postcss: {
// Default plugins
plugins: ['autoprefixer'],
// Stops the build if an error is found
failOnError: true
}
}
You can add new PostCSS plugins by overriding the option plugins
in your .febuild
file. Place them before the autoprefixer plugin.
postcss: {
plugins: ['mypostcssplugin', 'autoprefixer']
}
This configuration part refers to Webpack plugins.
Default configuration:
{
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(mode)
}
]
}
You can add new plugins by overriding the option plugins
or pushing them into the default configuration.
module.exports = (defaultConfig) => ({
plugins: [...defaultConfig.plugins, myPlugin]
});
Webpack optimizations for your JavaScript code: minimization, code splitting and tree shaking. Default configuration:
{
optimization: {
minimize: isProduction,
usedExports: isProduction,
runtimeChunk: {
name: 'commons/treeshaking.bundle.js'
},
splitChunks: {
cacheGroups: {
// this treeshake vendors (but keep unique vendors at the clientlibs it belongs )
vendors: {
test: mod => moduleIsVendor(mod.context, excludedFromVendors),
name: 'commons/vendors.bundle.js',
chunks: 'all',
minChunks: 2
},
// this treeshakes common imports, if are and more than 2 clientlibs
treeshaking: {
test: mod => !moduleIsVendor(mod.context, excludedFromVendors),
name: 'commons/treeshaking.bundle.js',
chunks: 'all',
minChunks: 2
}
}
}
}
}
If a module is imported into more than 2 files, it's extracted to a common file. There are 2 main common files:
treeshaking.bundle.js
: common code that reside in the project.vendors.bundle.js
: common code that is outside of the scope your project.
vendors.bundle.js
This is intended to extract reused third-party scripts that are imported in two or more modules to a different file, so it avoids duplication and this file can be loaded separately. Also it is good to separate those third-party from the regular tree shaking since this vendors sometimes might be best suited as an external option.
Advantages of having a separated vendor:
- Clear view of the impact of third-party on your code base.
- You can identify possible additions to externals (removing it completely from your code).
treeshaking.bundle.js
This is intended to optimize the codebase of the project, by code splitting the modules that are the building blocks of it, like core-js, babel and @your modules.