piratepoet/webpack.config.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

528 lines
13 KiB
JavaScript
Raw Normal View History

const webpack = require('webpack');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const WebpackTerserPlugin = require('terser-webpack-plugin');
const WebpackCopyPlugin = require('copy-webpack-plugin');
const path = require('path');
const wpScriptConfig = require('@wordpress/scripts/config/webpack.config');
const DependencyExtractionWebpackPlugin = require('@wordpress/dependency-extraction-webpack-plugin');
const globalPrefix = 'MailPoetLib';
const PRODUCTION_ENV = process.env.NODE_ENV === 'production';
const manifestSeed = {};
// Base config
const baseConfig = {
mode: PRODUCTION_ENV ? 'production' : 'development',
devtool: PRODUCTION_ENV ? undefined : 'eval-source-map',
cache: true,
bail: PRODUCTION_ENV,
context: __dirname,
2018-06-13 13:33:27 +01:00
watchOptions: {
aggregateTimeout: 300,
poll: true,
},
optimization: {
minimizer: [
new WebpackTerserPlugin({
terserOptions: {
// preserve identifier names for easier debugging & support
mangle: false,
},
2019-02-05 15:50:05 +03:00
parallel: false,
}),
],
},
output: {
publicPath: '', // This is needed to have correct names in WebpackManifestPlugin
path: path.join(__dirname, 'assets/dist/js'),
filename: (PRODUCTION_ENV) ? '[name].[fullhash:8].js' : '[name].js',
chunkFilename: (PRODUCTION_ENV) ? '[name].[fullhash:8].chunk.js' : '[name].chunk.js',
},
resolve: {
modules: [
'node_modules',
'assets/js/src',
],
fallback: {
fs: false,
// We need path polyfill so that eslint is able to lint webpack.config.js
// and it is imported in css module, but we don't use the functionality which requires it
path: require.resolve('path-browserify'),
},
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
handlebars: 'handlebars/dist/handlebars.js',
'backbone.marionette': 'backbone.marionette/lib/backbone.marionette',
'backbone.supermodel$': 'backbone.supermodel/build/backbone.supermodel.js',
'sticky-kit': 'vendor/jquery.sticky-kit.js',
interact$: 'interact.js/interact.js',
spectrum$: 'spectrum-colorpicker/spectrum.js',
'wp-js-hooks': path.resolve(__dirname, 'assets/js/src/hooks.js'),
blob$: 'blob-tmp/Blob.js',
chai: 'chai/index.js',
papaparse: 'papaparse/papaparse.min.js',
html2canvas: 'html2canvas/dist/html2canvas.js',
asyncqueue: 'vendor/jquery.asyncqueue.js',
2015-08-26 18:24:43 +03:00
},
},
plugins: [],
module: {
noParse: /node_modules\/lodash\/lodash\.js/,
2018-06-13 13:33:27 +01:00
rules: [
{
test: /\.(j|t)sx?$/,
2019-02-20 11:20:33 +01:00
exclude: /(node_modules|src\/vendor)/,
loader: 'babel-loader',
},
{
include: require.resolve('underscore'),
loader: 'expose-loader',
options: {
exposes: '_',
},
},
2018-06-06 15:13:39 +01:00
{
include: require.resolve('react-tooltip'),
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.ReactTooltip`,
},
2018-06-06 15:13:39 +01:00
},
{
include: require.resolve('react'),
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.React`,
},
},
{
include: require.resolve('react-dom'),
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.ReactDOM`,
},
},
{
include: require.resolve('react-router-dom'),
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.ReactRouter`,
},
},
{
include: require.resolve('react-string-replace'),
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.ReactStringReplace`,
},
},
{
include: path.resolve(__dirname, 'assets/js/src/hooks.js'),
loader: 'expose-loader',
options: {
exposes: {
globalName: `${globalPrefix}.Hooks`,
override: true,
},
},
},
{
test: /listing.jsx/i,
2018-06-13 13:33:27 +01:00
use: [
{
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.Listing`,
},
},
'babel-loader',
2018-06-13 13:33:27 +01:00
],
},
2019-05-15 15:09:14 +02:00
{
include: path.resolve(__dirname, 'assets/js/src/help-tooltip.jsx'),
2019-05-15 15:09:14 +02:00
use: [
{
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.HelpTooltip`,
},
},
'babel-loader',
],
2019-05-15 15:09:14 +02:00
},
{
include: path.resolve(__dirname, 'assets/js/src/common/index.ts'),
use: [
{
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.Common`,
},
},
'babel-loader',
],
},
{
include: /Blob.js$/,
loader: 'exports-loader',
options: {
exports: 'default window.Blob',
},
},
{
test: /backbone.supermodel/,
loader: 'exports-loader',
options: {
exports: 'default Backbone.SuperModel',
},
},
{
include: require.resolve('velocity-animate'),
loader: 'imports-loader',
options: {
imports: {
name: 'jQuery',
moduleName: 'jquery',
},
},
},
{
include: require.resolve('classnames'),
2018-06-13 13:33:27 +01:00
use: [
{
loader: 'expose-loader',
options: {
exposes: `${globalPrefix}.ClassNames`,
},
},
'babel-loader',
],
},
{
test: /node_modules\/tinymce/,
loader: 'string-replace-loader',
options: {
// prefix TinyMCE to avoid conflicts with other plugins
multiple: [
{
search: 'window\\.tinymce',
replace: 'window.mailpoetTinymce',
flags: 'g',
},
{
search: 'tinymce\\.util',
replace: 'window.mailpoetTinymce.util',
flags: 'g',
},
{
search: 'resolve\\(\'tinymce',
replace: 'resolve(\'mailpoetTinymce',
flags: 'g',
},
],
},
},
],
},
};
// Admin config
const adminConfig = {
name: 'admin',
entry: {
vendor: 'webpack_vendor_index.jsx',
mailpoet: 'webpack_mailpoet_index.jsx',
// Admin vendor contains libraries shared between free and premium plugin
admin_vendor: [
'react',
'react-dom',
require.resolve('react-router-dom'),
'react-string-replace',
'prop-types',
'classnames',
'lodash',
'help-tooltip.jsx',
'listing/listing.jsx',
'common/index.ts',
],
admin: 'webpack_admin_index.jsx',
newsletter_editor: 'newsletter_editor/webpack_index.jsx',
form_editor: 'form_editor/form_editor.jsx',
settings: 'settings/index.tsx',
},
plugins: [
...baseConfig.plugins,
new WebpackCopyPlugin({
patterns: [
{
from: 'node_modules/tinymce/skins/ui/oxide',
to: 'skins/ui/oxide',
},
],
}),
new webpack.ProvidePlugin({
process: 'process/browser',
}),
],
optimization: {
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
commons: {
name: 'commons',
chunks: 'initial',
minChunks: 2,
},
},
},
},
externals: {
jquery: 'jQuery',
},
};
// Public config
const publicConfig = {
name: 'public',
entry: {
public: 'webpack_public_index.jsx',
},
plugins: [
...baseConfig.plugins,
// replace MailPoet definition with a smaller version for public
new webpack.NormalModuleReplacementPlugin(
/mailpoet\.js/,
'./mailpoet_public.js'
),
],
externals: {
jquery: 'jQuery',
},
};
// Migrator config
const migratorConfig = {
name: 'mp2migrator',
New: Display the number of data to migrate Several fixes following the code review: - For styles we use Stylus. (http://stylus-lang.com/) In Stylus styles curly brackets and terminating semicolons are unnecessary. Indentation is sufficient to denote blocks of styles You can also use variables to avoid duplication (e.g. mentioning the same color multiple times) Vendor prefixes are not necessary. We use the Nib mixin for Stylus to handle those (http://tj.github.io/nib/) => DONE - `admin.js` bundle is included on all admin pages, so we need to ensure that migration fires only on the migration page and nowhere else. You can even create a separate bundle only for migration files, as they won't be necessary on other admin pages. => DONE - MP2MigratorAPI => MP2Migrator endpoint would be just as fine => DONE - For storing migration files, you can use the `Env::$temp_path` path => DONE - `proposeMigration()` the method name disagrees with the comment. Comment suggests it tests if migration can be or should be performed Method name suggests that it proposes doing the migration (to the user?) - not very clear => DONE: the new name is isMigrationNeeded() And not only does it test, it may also update the `mailpoet_migration_complete` option, which is confusing and is an unexpected side-effect. => DONE The migration class itself `MP2Migrator` shouldn't even care about _GET, _REQUEST or _POST arguments. It should only work with what is passed to it. => DONE - In views, please make sure all human-friendly texts use WP's gettext functions for translations (e.g. __('text')) => DONE
2017-04-18 19:15:12 +02:00
entry: {
mp2migrator: [
'mp2migrator.js',
],
New: Display the number of data to migrate Several fixes following the code review: - For styles we use Stylus. (http://stylus-lang.com/) In Stylus styles curly brackets and terminating semicolons are unnecessary. Indentation is sufficient to denote blocks of styles You can also use variables to avoid duplication (e.g. mentioning the same color multiple times) Vendor prefixes are not necessary. We use the Nib mixin for Stylus to handle those (http://tj.github.io/nib/) => DONE - `admin.js` bundle is included on all admin pages, so we need to ensure that migration fires only on the migration page and nowhere else. You can even create a separate bundle only for migration files, as they won't be necessary on other admin pages. => DONE - MP2MigratorAPI => MP2Migrator endpoint would be just as fine => DONE - For storing migration files, you can use the `Env::$temp_path` path => DONE - `proposeMigration()` the method name disagrees with the comment. Comment suggests it tests if migration can be or should be performed Method name suggests that it proposes doing the migration (to the user?) - not very clear => DONE: the new name is isMigrationNeeded() And not only does it test, it may also update the `mailpoet_migration_complete` option, which is confusing and is an unexpected side-effect. => DONE The migration class itself `MP2Migrator` shouldn't even care about _GET, _REQUEST or _POST arguments. It should only work with what is passed to it. => DONE - In views, please make sure all human-friendly texts use WP's gettext functions for translations (e.g. __('text')) => DONE
2017-04-18 19:15:12 +02:00
},
externals: {
jquery: 'jQuery',
mailpoet: 'MailPoet',
},
};
// Newsletter Editor Tests Config
const testConfig = {
name: 'test',
entry: {
vendor: 'webpack_vendor_index.jsx',
2015-08-26 18:24:43 +03:00
testNewsletterEditor: [
'webpack_mailpoet_index.jsx',
'newsletter_editor/webpack_index.jsx',
2015-08-26 18:24:43 +03:00
'components/config.spec.js',
'components/content.spec.js',
'components/heading.spec.js',
'components/history.spec.js',
'components/save.spec.js',
'components/sidebar.spec.js',
'components/styles.spec.js',
'components/communication.spec.js',
2015-08-26 18:24:43 +03:00
'blocks/automatedLatestContentLayout.spec.js',
'blocks/button.spec.js',
'blocks/container.spec.js',
'blocks/divider.spec.js',
'blocks/footer.spec.js',
'blocks/header.spec.js',
'blocks/image.spec.js',
'blocks/posts.spec.js',
'blocks/products.spec.js',
'blocks/social.spec.js',
'blocks/spacer.spec.js',
'blocks/text.spec.js',
2015-08-26 18:24:43 +03:00
],
},
output: {
path: path.join(__dirname, 'tests/javascript_newsletter_editor/testBundles'),
filename: '[name].js',
},
plugins: [
...baseConfig.plugins,
// replace MailPoet definition with a smaller version for public
new webpack.NormalModuleReplacementPlugin(
/mailpoet\.js/,
'./mailpoet_tests.js'
),
],
resolve: {
2018-06-13 13:33:27 +01:00
modules: [
'node_modules',
'assets/js/src',
'tests/javascript_newsletter_editor/newsletter_editor',
2015-08-26 18:24:43 +03:00
],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
2015-08-26 18:24:43 +03:00
alias: {
handlebars: 'handlebars/dist/handlebars.js',
'sticky-kit': 'vendor/jquery.sticky-kit.js',
'backbone.marionette': 'backbone.marionette/lib/backbone.marionette',
'backbone.supermodel$': 'backbone.supermodel/build/backbone.supermodel.js',
blob$: 'blob-tmp/Blob.js',
'wp-js-hooks': path.resolve(__dirname, 'assets/js/src/hooks.js'),
2015-08-26 18:24:43 +03:00
},
fallback: {
fs: false,
},
2015-08-26 18:24:43 +03:00
},
externals: {
jquery: 'jQuery',
interact: 'interact',
spectrum: 'spectrum',
},
};
// Form preview config
const formPreviewConfig = {
name: 'form_preview',
entry: {
form_preview: 'form_editor/form_preview.ts',
},
externals: {
jquery: 'jQuery',
},
};
2020-01-30 14:05:51 +01:00
// Block config
const postEditorBlock = {
name: 'post_editor_block',
entry: {
post_editor_block: 'post_editor_block/blocks.jsx',
},
};
// Marketing Optin config
function requestToExternal(request) {
const wcDepMap = {
'@woocommerce/settings': ['wc', 'wcSettings'],
'@woocommerce/blocks-checkout': ['wc', 'blocksCheckout'],
};
if (wcDepMap[request]) {
return wcDepMap[request];
}
// DependencyExtractionWebpackPlugin has native handling for @wordpress/*
// packages, for that handling to kick in, we must not return anything from
// function.
/* eslint-disable-next-line consistent-return, no-useless-return */
return;
}
function requestToHandle(request) {
const wcHandleMap = {
'@woocommerce/settings': 'wc-settings',
'@woocommerce/blocks-checkout': 'wc-blocks-checkout',
};
if (wcHandleMap[request]) {
return wcHandleMap[request];
}
// DependencyExtractionWebpackPlugin has native handling for @wordpress/*
// packages, for that handling to kick in, we must not return anything from
// function.
/* eslint-disable-next-line consistent-return, no-useless-return */
return;
}
const marketingOptinBlock = Object.assign({}, wpScriptConfig, {
name: 'marketing_optin_block',
entry: {
'marketing-optin-block': path.resolve(
process.cwd(),
'assets/js/src/marketing_optin_block',
'index.tsx'
),
'marketing-optin-block-frontend': path.resolve(
process.cwd(),
'assets/js/src/marketing_optin_block',
'frontend.ts'
),
},
output: {
filename: '[name].js',
path: path.resolve(process.cwd(), 'assets/dist/js/marketing_optin_block'),
},
module: Object.assign({}, wpScriptConfig.module, {
rules: [
...wpScriptConfig.module.rules,
{
test: /\.(t|j)sx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader?cacheDirectory',
options: {
presets: ['@wordpress/babel-preset-default'],
plugins: [
require.resolve('@babel/plugin-proposal-class-properties'),
require.resolve(
'@babel/plugin-proposal-nullish-coalescing-operator'
),
].filter(Boolean),
},
},
},
],
}),
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
plugins: [
...wpScriptConfig.plugins.filter(
(plugin) => plugin.constructor.name !== 'DependencyExtractionWebpackPlugin'
),
new DependencyExtractionWebpackPlugin({
injectPolyfill: true,
requestToExternal,
requestToHandle,
}),
new WebpackCopyPlugin({
patterns: [
{
from: 'assets/js/src/marketing_optin_block/block.json',
to: 'block.json',
},
],
}),
],
});
const configs = [
publicConfig,
adminConfig,
migratorConfig,
formPreviewConfig,
testConfig,
postEditorBlock,
marketingOptinBlock,
];
module.exports = configs.map((conf) => {
const config = Object.assign({}, conf);
if (config.name === 'marketing_optin_block') {
return config;
}
if (config.name !== 'test') {
config.plugins = config.plugins || [];
config.plugins.push(
new WebpackManifestPlugin({
// create single manifest file for all Webpack configs
seed: manifestSeed,
})
);
}
return Object.assign({}, baseConfig, config);
});