Files
piratepoet/webpack.config.js
Rostislav Wolny bb0fd44d95 Add fallback dummy nodejs path module
The path is required in css module which we use for parsing
custom css string in the form editor.
We don't use functionality which is dependent on nodejs path module
so we can use "dummy" module. Alternatively we could install a polyfill for brower
for the path module but it would increase a package size with functions we don't use.
[MAILPOET-3214]
2021-09-22 11:56:49 +02:00

401 lines
11 KiB
JavaScript

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 del = require('del');
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,
watchOptions: {
aggregateTimeout: 300,
poll: true
},
optimization: {
minimizer: [
new webpackTerserPlugin({
terserOptions: {
// preserve identifier names for easier debugging & support
mangle: false,
},
parallel: false,
}),
],
},
output: {
path: path.join(__dirname, 'assets/dist/js'),
filename: (PRODUCTION_ENV) ? '[name].[hash:8].js' : '[name].js',
chunkFilename: (PRODUCTION_ENV) ? '[name].[hash:8].chunk.js' : '[name].chunk.js',
jsonpFunction: 'mailpoetJsonp'
},
resolve: {
modules: [
'node_modules',
'assets/js/src',
],
fallback: {
fs: false,
path: false, // path is used in css module, but we don't use the functionality which requires it
},
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',
'papaparse': 'papaparse/papaparse.min.js',
'html2canvas': 'html2canvas/dist/html2canvas.js',
'asyncqueue': 'vendor/jquery.asyncqueue.js',
},
},
plugins: [],
module: {
noParse: /node_modules\/lodash\/lodash\.js/,
rules: [
{
test: /\.(j|t)sx?$/,
exclude: /(node_modules|src\/vendor)/,
loader: 'babel-loader',
},
{
test: /form_editor\.js$/,
loader: 'expose-loader?WysijaForm',
},
{
include: require.resolve('codemirror'),
loader: 'expose-loader?CodeMirror',
},
{
include: require.resolve('backbone'),
loader: 'expose-loader?Backbone',
},
{
include: require.resolve('underscore'),
loader: 'expose-loader?_',
},
{
include: require.resolve('react-tooltip'),
loader: 'expose-loader?' + globalPrefix + '.ReactTooltip',
},
{
include: require.resolve('react'),
loader: 'expose-loader?' + globalPrefix + '.React',
},
{
include: require.resolve('react-dom'),
loader: 'expose-loader?' + globalPrefix + '.ReactDOM',
},
{
include: require.resolve('react-router-dom'),
use: 'expose-loader?' + globalPrefix + '.ReactRouter',
},
{
include: require.resolve('react-string-replace'),
loader: 'expose-loader?' + globalPrefix + '.ReactStringReplace',
},
{
include: path.resolve(__dirname, 'assets/js/src/hooks.js'),
use: 'expose-loader?' + globalPrefix + '.Hooks',
},
{
test: /listing.jsx/i,
use: [
'expose-loader?' + globalPrefix + '.Listing',
'babel-loader'
],
},
{
include: path.resolve(__dirname, 'assets/js/src/help-tooltip.jsx'),
use: [
'expose-loader?' + globalPrefix + '.HelpTooltip',
'babel-loader',
]
},
{
include: path.resolve(__dirname, 'assets/js/src/common/index.ts'),
use: [
'expose-loader?' + globalPrefix + '.Common',
'babel-loader',
]
},
{
include: /Blob.js$/,
loader: 'exports-loader?window.Blob',
},
{
test: /backbone.supermodel/,
loader: 'exports-loader?Backbone.SuperModel',
},
{
include: require.resolve('handlebars'),
loader: 'expose-loader?Handlebars',
},
{
include: require.resolve('velocity-animate'),
loader: 'imports-loader?jQuery=jquery',
},
{
include: require.resolve('classnames'),
use: [
'expose-loader?' + 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: [
'react',
'react-dom',
require.resolve('react-router-dom'),
'react-string-replace',
'prop-types',
'classnames',
'lodash',
'@emotion/react',
'@emotion/styled',
'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'
},
],
}),
],
optimization: {
runtimeChunk: {
name: 'vendor',
},
splitChunks: {
cacheGroups: {
chunks: 'all',
default: false,
vendors: false,
vendor: {
name: 'vendor',
chunks: (chunk) => chunk.name === 'vendor',
priority: 1,
enforce: true,
},
admin_vendor_chunk: {
name: 'admin_vendor_chunk',
test: (module, chunks) => {
// add all modules from 'admin_vendor' entrypoint
if (chunks.some((chunk) => chunk.name === 'admin_vendor')) {
return true;
}
// add admin/form_editor_legacy/newsletter_editor shared modules
const filteredChunks = chunks.filter((chunk) => {
return ['admin', 'newsletter_editor', 'form_editor', 'settings'].includes(chunk.name);
});
return filteredChunks.length > 1;
},
enforce: true,
chunks: (chunk) => ['admin_vendor', 'admin', 'newsletter_editor'].includes(chunk.name),
priority: 0,
},
}
}
},
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',
entry: {
mp2migrator: [
'mp2migrator.js'
]
},
externals: {
'jquery': 'jQuery',
'mailpoet': 'MailPoet'
}
};
// Newsletter Editor Tests Config
const testConfig = {
name: 'test',
entry: {
vendor: 'webpack_vendor_index.jsx',
testNewsletterEditor: [
'webpack_mailpoet_index.jsx',
'newsletter_editor/webpack_index.jsx',
'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',
'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',
],
},
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: {
modules: [
'node_modules',
'assets/js/src',
'tests/javascript_newsletter_editor/newsletter_editor'
],
extensions: ['.js', '.jsx', '.ts', '.tsx'],
alias: {
'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'),
},
fallback: {
fs: false,
},
},
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',
},
};
// Block config
const postEditorBlock = {
name: 'post_editor_block',
entry: {
post_editor_block: 'post_editor_block/blocks.jsx',
},
};
module.exports = [adminConfig, publicConfig, migratorConfig, formPreviewConfig, testConfig, postEditorBlock].map((config) => {
if (config.name !== 'test') {
config.plugins = config.plugins || [];
config.plugins.push(
new WebpackManifestPlugin({
// create single manifest file for all Webpack configs
seed: manifestSeed,
})
);
}
// Clean output paths before build
if (config.output && config.output.path) {
del.sync([path.resolve(config.output.path, '**/*')]);
}
return Object.assign({}, baseConfig, config);
});