Minimal configuration to run a development server and build your assets with Webpack.
Install the package in your project:
npm install --save-dev @studiometa/webpack-configCreate a meta.config.js file at the root of yout project:
// meta.config.mjs
import { defineConfig } from '@studiometa/webpack-config';
import { twig, yaml, tailwindcss, prototyping, eslint, stylelint, hash, https } from '@studiometa/webpack-config/presets';
import { vue } from '@studiometa/webpack-config-preset-vue-3';
export default defineConfig({
src: [
'./path/to/src/js/*.js',
'./path/to/src/css/*.scss',
],
dist: './path/to/dist',
public: '/path/to/dist',
/**
* Define which target to use when creating the bundle.
* An array of targets will create a bundle for each target.
* Defaults to `legacy`.
*
* @type {'modern'|'legacy'|Array<'modern'|'legacy'>}
* @optional
*/
target: ['modern', 'legacy'],
/**
* Analyze the bundle with the WebpackBundleAnalyzer plugin.
* @type {Boolean}
* @optional
*/
analyze: false,
/**
* Merge all initial CSS chunks into one file.
* Use a RegExp or a function to exclude some files:
* ```js
* mergeCSS: /^(?!.*css\/do-not-merge\.scss).*$/,
* mergeCSS(module, chunk) {
* return module.constructor.name === 'CssModule';
* },
* ```
* @type {Boolean|RegExp|Function}
* @optional
*/
mergeCSS: false,
/**
* Extends the Webpack configuration before merging
* with the environment specific configurations.
* @type {Function}
* @optional
*/
webpack(config, isDev) {},
/**
* Extends the development Webpack configuration.
* @param {WebpackConfig} devConfig The Webpack development config.
* @type {Function}
* @optional
*/
webpackDev(devConfig) {},
/**
* Extends the production Webpack configuration.
* @param {WebpackConfig} devConfig The Webpack production config.
* @type {Function}
* @optional
*/
webpackProd(prodConfig) {},
/**
* Configure the `sass-loader` options.
* @type {Objet}
* @optional
* @see https://github.com/webpack-contrib/sass-loader#sassoptions
*/
sassOptions: {},
/**
* Configure the browserSync server if you do not use a proxy by setting
* this property to `true` or a BrowserSync server configuration object.
* If the property is a function, it will be used to alter the server
* configuraton and instance in proxy mode.
* @see https://browsersync.io/docs/options#option-server
* @type {Boolean|Object|Function}
* @optional
*/
server: true,
server(bsConfig, bs) {},
/**
* Watch for file changes in dev mode and:
* - reload the browser
* - or execute a callback
* @see https://browsersync.io/docs/api#api-watch
* @type {Array<String|Array>}
* @optional
*/
watch: [
// Watch for changes on all PHP files and reload the browser
'*.php',
// Watch for all events on all HTML files and execute the callback
[
'*.html',
(event, file, bs, bsConfig) => {
if (event === 'change') {
bs.reload();
}
},
],
],
/**
* Use presets to apply pre-made configurations.
* @type {Array<String|Array<String,Object>>}
* @optional
*/
presets: [
eslint(), // use the `eslint` preset
stylelint(), // use the `stylelint` preset
twig(), // use the `twig` preset
tailwindcss(), // use the `tailwindcss` preset,
yaml(), // use the `yaml` preset,
vue(), // use the Vue 3 preset,
hash(), // use the content hash preset
https(), // use the https preset
{
name: 'my-custom-preset',
handler(metaConfig, { extendWebpack, extendBrowsersync, isDev }) {
// ...
},
},
],
};Configure a .env file with one of the following variable defining your application domain to use for the proxy:
APP_HOST=local.fqdn.com
APP_HOSTNAME=local.fqdn.com
APP_URL=https://local.fqdn.comYou can then start the development server:
node_modules/.bin/meta devOr watch for changes to build you assets:
node_modules/.bin/meta watchAnd build your assets for production:
node_modules/.bin/meta buildYou can analyze your bundle(s) with the --analyze (or -a) argument:s
node_modules/.bin/meta build --analyze- Raw imports with the
?rawquery - SVG to Vue component with the
?as-vue-component(requires a vue preset)
Presets can be used to extend the CLI configuration elegantly. The following presets are shipped with the package and can be used without installing any more dependencies:
Read their documentation below to find out how to use and configure them.
Custom presets can be used by using the path of a JS file (relative to the meta.config.js file):
// meta.config.mjs
import { defineConfig } from '@studiometa/webpack-config';
import myPreset from './my-preset.mjs';
export default defineConfig({
presets: [
myPreset({ option: true })
],
})
// my-preset.mjs
export default function myPreset(options) {
return {
name: 'my-preset',
async handler(metaConfig, { extendWebpack, isDev }) {
metaConfig.public = 'auto';
await extendWebpack(metaConfig, async (webpackConfig) => {
webpackConfig.optimization.minimize = false;
});
}
}
}Add ESLint validation with eslint-webpack-plugin.
The options object is directly passed to the ESLintPlugin constructor, see the package documentation for details.
Use it without configuration:
import { defineConfig } from '@studiometa/webpack-config';
import { eslint } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [eslint()],
});Or pass custom options:
import { defineConfig } from '@studiometa/webpack-config';
import { eslint } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [
eslint({
fix: false,
}),
],
});Add StyleLint validation with stylelint-webpack-plugin.
The options object is directly passed to the StylelintPlugin constructor, see the package documentation for details.
Use it without configuration:
import { defineConfig } from '@studiometa/webpack-config';
import { stylelint } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [stylelint()],
});Or pass custom options:
import { defineConfig } from '@studiometa/webpack-config';
import { stylelint } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [
stylelint({
fix: false,
}),
],
});Add the twig-html-loader to the Webpack configuration.
The options object is directly passed to the twig-html-loader.
Use it without configuration:
import { defineConfig } from '@studiometa/webpack-config';
import { twig } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [twig()],
});Or configure the loader options:
import { defineConfig } from '@studiometa/webpack-config';
import { twig } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [
twig({
debug: true,
}),
],
});Add Tailwind CSS to the PostCSS configuration and enable a preview of your Tailwind configuration in dev mode with tailwind-config-viewer.
path(String): the absolute path to the Tailwind CSS entry file
Use it without configuration:
import { defineConfig } from '@studiometa/webpack-config';
import { tailwindcss } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [tailwindcss()],
});If the meta CLI fails to resolve the tailwindcss package, specify its path:
import path from 'node:path';
import { defineConfig } from '@studiometa/webpack-config';
import { twig } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [
tailwindcss({
path: path.resolve('./node_modules/tailwindcss/lib/index.js'),
}),
],
});The default route for the Tailwind config viewer is /_tailwind/. It is customisable with the configViewerPath options:
import { defineConfig } from '@studiometa/webpack-config';
import { twig } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [
tailwindcss({
configViewerPath: '/__custom_tailwind_viewer_path',
}),
],
});Add support for the import of YAML files with the js-yaml-loader.
loaderOptions(Object): options for thejs-yaml-loader
import { defineConfig } from '@studiometa/webpack-config';
import { yaml } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [yaml()],
});Add support for Vue 2 or 3. The presets for Vue are available in two different packages, as their dependencies can not be installed in a single one. You will have to install the package corresponding to the version you want to use in your project:
# For Vue 2
npm install --save-dev @studiometa/webpack-config-preset-vue-2
# Or for Vue 3
npm install --save-dev @studiometa/webpack-config-preset-vue-3import { defineConfig } from '@studiometa/webpack-config';
import vue from '@studiometa/webpack-config-preset-vue-3';
export default defineConfig({
presets: [vue()],
});Add runtime polyfills based on actual usage while keeping esbuild-loader in the pipeline. This preset is available as a separate package:
npm install --save-dev @studiometa/webpack-config-preset-polyfillsimport { defineConfig } from '@studiometa/webpack-config';
import { polyfills } from '@studiometa/webpack-config-preset-polyfills';
export default defineConfig({
presets: [polyfills()],
});Add content hash to filenames in production.
This preset has no options.
import { defineConfig } from '@studiometa/webpack-config';
import { hash } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [hash()],
});Generate an SSL certificate with mkcert for the local dev server. Can be useful when proxying to an HTTPS only url in dev mode.
This preset has no options.
import { defineConfig } from '@studiometa/webpack-config';
import { https } from '@studiometa/webpack-config/presets';
export default defineConfig({
presets: [https()],
});This project uses a trunk-based workflow with main as the default branch. Open a pull request targeting main for feature, fix, and maintenance branches.
Do not edit CHANGELOG.md. Each pull request adds a fragment in .changelog/<slug>.md, where the slug is the branch name without its prefix (feature/foo → foo.md). A fragment only contains ### Added|Changed|Deprecated|Removed|Fixed|Security|Dependencies headings, each followed by its entries:
### Added
- **@studiometa/webpack-config-preset-polyfills:** Add a preset to inject `core-js` polyfillsDo not write the pull request number: the release adds it. The Changelog check fails when a pull request changes a published package (packages/webpack-config, packages/preset-*, packages/php) without a fragment; set the no-changelog label for changes users do not see (tests, refactors, tooling). See weareikko/changelog for the format.
Each merge into main releases what its fragments describe. The Release workflow (release.yml) runs the tests, then the weareikko/changelog action computes the next version from the fragments, folds them into CHANGELOG.md, bumps the version of all packages (the version script also sets it in composer.json for Packagist), commits Release <version>, tags it (no v prefix) and creates the GitHub release. The workflow then publishes the packages to npm. A merge without fragment releases nothing. Pull requests from renovate[bot] and dependabot[bot] need no fragment: the release lists them under Dependencies.
To force a bump, run the workflow by hand:
gh workflow run release.yml -R studiometa/webpack-config -f version=major # or minor / patchTo release prereleases, add a .changelog/prerelease file with one identifier (alpha, beta or rc): each merge with fragments then releases the next prerelease (6.5.0-rc.0, 6.5.0-rc.1…). A prerelease is published on the next npm tag and marked as a prerelease on GitHub; any other version is published on the latest npm tag. To install a prerelease: npm install @studiometa/webpack-config@next. To release the stable version, delete .changelog/prerelease: its merge releases it. See Prereleases.
The packages are published with npm trusted publishing (OIDC): there is no npm token, and the publish job must stay in release.yml. Each package has its own publish step, and each step skips a version that npm already has. When the publish job fails (for example on a network error), use "Re-run failed jobs" on the workflow run: it publishes only the packages that are missing.