Last active
March 14, 2022 10:21
-
-
Save wpscholar/261141cf7b2bf4efd45cb86ad0a43ff2 to your computer and use it in GitHub Desktop.
Webpack 4 Config for WordPress plugin, theme, and block development
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
**/*.min.js | |
**/*.build.js | |
**/node_modules/** | |
**/vendor/** | |
build | |
coverage | |
cypress | |
node_modules | |
vendor |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"root": true, | |
"parser": "babel-eslint", | |
"extends": [ | |
"wordpress", | |
"plugin:react/recommended", | |
"plugin:jsx-a11y/recommended", | |
"plugin:jest/recommended" | |
], | |
"env": { | |
"browser": false, | |
"es6": true, | |
"node": true, | |
"mocha": true, | |
"jest/globals": true | |
}, | |
"parserOptions": { | |
"sourceType": "module", | |
"ecmaFeatures": { | |
"jsx": true | |
} | |
}, | |
"globals": { | |
"wp": true, | |
"wpApiSettings": true, | |
"window": true, | |
"document": true | |
}, | |
"plugins": [ | |
"react", | |
"jsx-a11y", | |
"jest" | |
], | |
"settings": { | |
"react": { | |
"pragma": "wp" | |
} | |
}, | |
"rules": { | |
"array-bracket-spacing": [ | |
"error", | |
"always" | |
], | |
"brace-style": [ | |
"error", | |
"1tbs" | |
], | |
"camelcase": [ | |
"error", | |
{ | |
"properties": "never" | |
} | |
], | |
"comma-dangle": [ | |
"error", | |
"always-multiline" | |
], | |
"comma-spacing": "error", | |
"comma-style": "error", | |
"computed-property-spacing": [ | |
"error", | |
"always" | |
], | |
"constructor-super": "error", | |
"dot-notation": "error", | |
"eol-last": "error", | |
"eqeqeq": "error", | |
"func-call-spacing": "error", | |
"indent": [ | |
"error", | |
"tab", | |
{ | |
"SwitchCase": 1 | |
} | |
], | |
"jsx-a11y/label-has-for": [ | |
"error", | |
{ | |
"required": "id" | |
} | |
], | |
"jsx-a11y/media-has-caption": "off", | |
"jsx-a11y/no-noninteractive-tabindex": "off", | |
"jsx-a11y/role-has-required-aria-props": "off", | |
"jsx-quotes": "error", | |
"key-spacing": "error", | |
"keyword-spacing": "error", | |
"lines-around-comment": "off", | |
"no-alert": "error", | |
"no-bitwise": "error", | |
"no-caller": "error", | |
"no-console": "error", | |
"no-const-assign": "error", | |
"no-debugger": "error", | |
"no-dupe-args": "error", | |
"no-dupe-class-members": "error", | |
"no-dupe-keys": "error", | |
"no-duplicate-case": "error", | |
"no-duplicate-imports": "error", | |
"no-else-return": "error", | |
"no-eval": "error", | |
"no-extra-semi": "error", | |
"no-fallthrough": "error", | |
"no-lonely-if": "error", | |
"no-mixed-operators": "error", | |
"no-mixed-spaces-and-tabs": "error", | |
"no-multiple-empty-lines": [ | |
"error", | |
{ | |
"max": 1 | |
} | |
], | |
"no-multi-spaces": "error", | |
"no-multi-str": "off", | |
"no-negated-in-lhs": "error", | |
"no-nested-ternary": "error", | |
"no-redeclare": "error", | |
"no-restricted-syntax": [ | |
"error", | |
{ | |
"selector": "ImportDeclaration[source.value=/^@wordpress\\u002F.+\\u002F/]", | |
"message": "Path access on WordPress dependencies is not allowed." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^blocks$/]", | |
"message": "Use @wordpress/blocks as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^components$/]", | |
"message": "Use @wordpress/components as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^date$/]", | |
"message": "Use @wordpress/date as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^editor$/]", | |
"message": "Use @wordpress/editor as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^element$/]", | |
"message": "Use @wordpress/element as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^i18n$/]", | |
"message": "Use @wordpress/i18n as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^data$/]", | |
"message": "Use @wordpress/data as import path instead." | |
}, | |
{ | |
"selector": "ImportDeclaration[source.value=/^utils$/]", | |
"message": "Use @wordpress/utils as import path instead." | |
}, | |
{ | |
"selector": "CallExpression[callee.name=/^__|_n|_x$/]:not([arguments.0.type=/^Literal|BinaryExpression$/])", | |
"message": "Translate function arguments must be string literals." | |
}, | |
{ | |
"selector": "CallExpression[callee.name=/^_n|_x$/]:not([arguments.1.type=/^Literal|BinaryExpression$/])", | |
"message": "Translate function arguments must be string literals." | |
}, | |
{ | |
"selector": "CallExpression[callee.name=_nx]:not([arguments.2.type=/^Literal|BinaryExpression$/])", | |
"message": "Translate function arguments must be string literals." | |
} | |
], | |
"no-shadow": "error", | |
"no-undef": "error", | |
"no-undef-init": "error", | |
"no-unreachable": "error", | |
"no-unsafe-negation": "error", | |
"no-unused-expressions": "error", | |
"no-unused-vars": "error", | |
"no-useless-computed-key": "error", | |
"no-useless-constructor": "error", | |
"no-useless-return": "error", | |
"no-var": "error", | |
"no-whitespace-before-property": "error", | |
"object-curly-spacing": [ | |
"error", | |
"always" | |
], | |
"prefer-const": "error", | |
"quote-props": [ | |
"error", | |
"as-needed" | |
], | |
"react/display-name": "off", | |
"react/jsx-curly-spacing": [ | |
"error", | |
{ | |
"when": "never", | |
"children": true | |
} | |
], | |
"react/jsx-equals-spacing": "error", | |
"react/jsx-indent": [ | |
"error", | |
"tab" | |
], | |
"react/jsx-indent-props": [ | |
"error", | |
"tab" | |
], | |
"react/jsx-key": "error", | |
"react/jsx-tag-spacing": "error", | |
"react/no-children-prop": "off", | |
"react/no-find-dom-node": "warn", | |
"react/prop-types": "off", | |
"semi": "error", | |
"semi-spacing": "error", | |
"space-before-blocks": [ | |
"error", | |
"always" | |
], | |
"space-before-function-paren": [ | |
"error", | |
"never" | |
], | |
"space-in-parens": [ | |
"error", | |
"always" | |
], | |
"space-infix-ops": [ | |
"error", | |
{ | |
"int32Hint": false | |
} | |
], | |
"space-unary-ops": [ | |
"error" | |
], | |
"template-curly-spacing": [ | |
"error", | |
"always" | |
], | |
"valid-jsdoc": [ | |
"error", | |
{ | |
"requireReturn": false | |
} | |
], | |
"valid-typeof": "error", | |
"yoda": "off" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "my-thing", | |
"description": "A description of my thing.", | |
"author": "Micah Wood <[email protected]> (http://wpscholar.com)", | |
"license": "proprietary", | |
"private": true, | |
"scripts": { | |
"build": "cross-env NODE_ENV=production webpack", | |
"lint": "eslint build/js/**/*", | |
"start": "webpack --watch", | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"dependencies": { | |
"classnames": "^2.2.5" | |
}, | |
"devDependencies": { | |
"@babel/core": "^7.1.2", | |
"@wordpress/babel-plugin-makepot": "^2.1.1", | |
"@wordpress/babel-preset-default": "^3.0.0", | |
"@wordpress/browserslist-config": "^2.1.3", | |
"@wordpress/i18n": "^3.0.0", | |
"ajv": "^6.5.4", | |
"autoprefixer": "^9.1.5", | |
"babel-eslint": "^10.0.1", | |
"babel-loader": "^8.0.4", | |
"babel-plugin-transform-class-properties": "^6.24.1", | |
"cross-env": "^5.0.1", | |
"css-loader": "^1.0.0", | |
"eslint": "^5.6.1", | |
"eslint-config-wordpress": "^2.0.0", | |
"eslint-plugin-jest": "^21.6.1", | |
"eslint-plugin-jsx-a11y": "^6.0.3", | |
"eslint-plugin-react": "^7.5.1", | |
"eslint-plugin-wordpress": "^0.1.0", | |
"file-loader": "^2.0.0", | |
"import-glob": "^1.5.0", | |
"mini-css-extract-plugin": "^0.4.0", | |
"node-sass": "^4.9.0", | |
"node-sass-glob-importer": "^5.1.2", | |
"postcss-loader": "^3.0.0", | |
"raw-loader": "^0.5.1", | |
"sass-loader": "^7.0.1", | |
"style-loader": "^0.23.0", | |
"webpack": "^4.20.2", | |
"webpack-cli": "^3.1.1" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
const autoprefixer = require( 'autoprefixer' ); | |
const fs = require( 'fs' ); | |
const globImporter = require( 'node-sass-glob-importer' ); | |
const browsers = require( '@wordpress/browserslist-config' ); | |
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' ); | |
const path = require( 'path' ); | |
const webpack = require( 'webpack' ); | |
module.exports = function() { | |
const mode = process.env.NODE_ENV || 'development'; | |
const extensionPrefix = mode === 'production' ? '.min' : ''; | |
// This is the URL path relative to the root domain. | |
const publicPath = '/wp-content/mu-plugins/blocks/'; | |
// These are the paths where different types of resources should end up. | |
const paths = { | |
css: 'assets/css/', | |
img: 'assets/img/', | |
font: 'assets/font/', | |
js: 'assets/js/', | |
lang: 'languages/', | |
}; | |
// The property names will be the file names, the values are the files that should be included. | |
const entry = { | |
blocks: [ | |
'./build/scss/blocks.scss', | |
], | |
editor: [ | |
'./build/js/editor.js', | |
'./build/scss/editor.scss', | |
], | |
}; | |
const loaders = { | |
css: { | |
loader: 'css-loader', | |
options: { | |
sourceMap: true, | |
}, | |
}, | |
postCss: { | |
loader: 'postcss-loader', | |
options: { | |
plugins: [ | |
autoprefixer( { | |
browsers, | |
flexbox: 'no-2009', | |
} ), | |
], | |
sourceMap: true, | |
}, | |
}, | |
sass: { | |
loader: 'sass-loader', | |
options: { | |
importer: globImporter(), | |
sourceMap: true, | |
}, | |
}, | |
}; | |
const config = { | |
mode, | |
entry, | |
output: { | |
path: path.join( __dirname, '/' ), | |
publicPath, | |
filename: `${ paths.js }[name]${ extensionPrefix }.js`, | |
}, | |
externals: { | |
'@wordpress/a11y': 'wp.a11y', | |
'@wordpress/components': 'wp.components', // Not really a package. | |
'@wordpress/blocks': 'wp.blocks', // Not really a package. | |
'@wordpress/data': 'wp.data', // Not really a package. | |
'@wordpress/date': 'wp.date', // Not really a package. | |
'@wordpress/element': 'wp.element', // Not really a package. | |
'@wordpress/hooks': 'wp.hooks', | |
'@wordpress/i18n': 'wp.i18n', | |
'@wordpress/utils': 'wp.utils', // Not really a package | |
backbone: 'Backbone', | |
jquery: 'jQuery', | |
lodash: 'lodash', | |
moment: 'moment', | |
react: 'React', | |
'react-dom': 'ReactDOM', | |
tinymce: 'tinymce', | |
}, | |
module: { | |
rules: [ | |
{ | |
enforce: 'pre', | |
test: /\.js|.jsx/, | |
loader: 'import-glob', | |
exclude: /(node_modules)/, | |
}, | |
{ | |
test: /\.js|.jsx/, | |
loader: 'babel-loader', | |
query: { | |
presets: [ | |
'@wordpress/default', | |
], | |
plugins: [ | |
[ | |
'@wordpress/babel-plugin-makepot', | |
{ | |
'output': `${ paths.lang }translation.pot`, | |
} | |
], | |
'transform-class-properties', | |
], | |
}, | |
exclude: /(node_modules|bower_components)/, | |
}, | |
{ | |
test: /\.html$/, | |
loader: 'raw-loader', | |
exclude: /node_modules/, | |
}, | |
{ | |
test: /\.css$/, | |
use: [ | |
MiniCssExtractPlugin.loader, | |
loaders.css, | |
loaders.postCss, | |
], | |
exclude: /node_modules/, | |
}, | |
{ | |
test: /\.scss$/, | |
use: [ | |
MiniCssExtractPlugin.loader, | |
loaders.css, | |
loaders.postCss, | |
loaders.sass, | |
], | |
exclude: /node_modules/, | |
}, | |
{ | |
test: /\.(ttf|eot|svg|woff2?)(\?v=[0-9]\.[0-9]\.[0-9])?$/, | |
use: [ | |
{ | |
loader: 'file-loader', | |
options: { | |
name: '[name].[ext]', | |
outputPath: paths.font, | |
}, | |
}, | |
], | |
exclude: /(assets)/, | |
}, | |
], | |
}, | |
plugins: [ | |
new MiniCssExtractPlugin( { | |
filename: `${ paths.css }[name]${ extensionPrefix }.css`, | |
} ), | |
new webpack.DefinePlugin( { | |
'process.env.NODE_ENV': JSON.stringify( mode ), | |
} ), | |
function() { | |
// Custom webpack plugin - remove generated JS files that aren't needed | |
this.hooks.done.tap( 'webpack', function( stats ) { | |
stats.compilation.chunks.forEach( chunk => { | |
if ( ! chunk.entryModule._identifier.includes( '.js' ) ) { | |
chunk.files.forEach( file => { | |
if ( file.includes( '.js' ) ) { | |
fs.unlinkSync( path.join( __dirname, `/${ file }` ) ); | |
} | |
} ); | |
} | |
} ); | |
} ); | |
}, | |
], | |
}; | |
if ( mode !== 'production' ) { | |
config.devtool = 'source-map'; | |
} | |
return config; | |
}; |
@jackjwilliams A new file will be created for each entry point. You can have as many entry points as you want. See https://gist.github.com/wpscholar/261141cf7b2bf4efd45cb86ad0a43ff2#file-webpack-config-js-L29
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm new to WordPress block development (but familiar with React / Webpack), but one thing I don't understand: how do you separate editor.css from style.css loading? Webpack puts them all together in one file. So I can't bundle an editor.css and styles.css separately.