blob: cf1e816322e3894d40dd681916ae3c38e8d57f6c [file] [log] [blame]
const webpack = require('webpack');
const path = require('path');
const json5 = require('json5');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const WebpackShellPluginNext = require('webpack-shell-plugin-next');
// Pontoon uses their own locale set. This array lets us convert those locales
// to the ones accepted by Chrome, Firefox, etc.
const localeOverrides = [
{
pontoonLocale: 'pt-rBR',
webExtLocale: 'pt_BR',
},
{
pontoonLocale: 'pt-rBR',
webExtLocale: 'pt_PT',
},
];
module.exports = (env, args) => {
// NOTE: When adding an entry, add the corresponding source map file to
// web_accessible_resources in //templates/manifest.gjson.
const entry = {
// Content scripts
communityConsoleMain:
'./src/entryPoints/communityConsole/contentScripts/main.ts',
communityConsoleStart:
'./src/entryPoints/communityConsole/contentScripts/start.ts',
publicForum: './src/contentScripts/publicForum.js',
publicThread: './src/contentScripts/publicThread.js',
publicThreadStart: './src/entryPoints/twBasic/thread/start.ts',
publicGuide: './src/contentScripts/publicGuide.js',
publicGuideStart: './src/contentScripts/publicGuideStart.js',
publicProfile: './src/contentScripts/publicProfile.js',
publicProfileStart: './src/contentScripts/publicProfileStart.js',
profileIndicator: './src/contentScripts/profileIndicator.js',
// Programatically injected content scripts
handleInstall: './src/contentScripts/communityConsole/handleInstall.js',
handleUpdate: './src/contentScripts/communityConsole/handleUpdate.js',
// Injected JS
profileIndicatorInject: './src/injections/profileIndicator.js',
batchLockInject: './src/injections/batchLock.js',
xhrInterceptorInject: './src/entryPoints/communityConsole/injections/xhrProxy.ts',
extraInfoInject: './src/injections/extraInfo.js',
litComponentsInject: './src/injections/litComponentsInject.js',
updateHandlerLitComponents:
'./src/injections/updateHandlerLitComponents.js',
// Options page
optionsCommon: './src/options/optionsCommon.js',
// Workflow manager
workflowManager: './src/features/workflows/core/manager/index.js',
// Common CSS
mdcStyles: './src/mdc/index.js',
// Compiled Sass
ccDarkTheme: './src/features/ccDarkTheme/core/styles/main.scss?asCSSFile',
// Background script (or service worker for MV3)
bg: './src/bg.js',
};
// NOTE: When adding an entry, add the corresponding source map file to
// web_accessible_resources in //templates/manifest.gjson.
const styles = [
{
origin: './src/features/enhancedAnnouncementsDot/ui/styles.css',
destination: 'css/enhanced_announcements_dot.css',
},
{
origin: './src/features/fixedToolbar/ui/styles.css',
destination: 'css/fixed_toolbar.css',
},
{
origin: './src/features/imageMaxHeight/ui/styles.css',
destination: 'css/image_max_height.css',
},
{
origin: './src/features/increaseContrast/ui/styles.css',
destination: 'css/increase_contrast.css',
},
{
origin: './src/features/repositionExpandThread/ui/styles.css',
destination: 'css/reposition_expand_thread.css',
},
{
origin: './src/features/stickySidebarHeaders/ui/styles.css',
destination: 'css/sticky_sidebar_headers.css',
},
];
const outputPath = path.join(__dirname, 'dist', env.browser_target);
const overridenLocalePaths =
localeOverrides.map(l => '**/_locales/' + l.pontoonLocale);
let preprocessorLoader = {
loader: 'webpack-preprocessor-loader',
options: {
params: {
browser_target: env.browser_target,
production: args.mode == 'production',
canary: !!env.canary
},
},
};
return {
entry,
output: {
filename: '[name].bundle.js',
path: outputPath,
clean: true,
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].bundle.css',
}),
new WebpackShellPluginNext({
onBuildStart: {
scripts: ['make lit_localize_build'],
blocking: true,
},
onBuildEnd: {
scripts:
['genmanifest -template templates/manifest.gjson -dest ' +
path.join(outputPath, 'manifest.json') + ' ' +
env.browser_target]
}
}),
new CopyWebpackPlugin({
patterns: [
{
from: path.join(
__dirname, 'src/icons', env.canary ? 'canary' : 'regular'),
to: path.join(outputPath, 'icons'),
},
{
from: path.join(__dirname, 'src/static'),
to: outputPath,
globOptions: {
ignore: ['**/OWNERS', '**.md', ...overridenLocalePaths],
}
},
...getStylesCopyPatterns(styles),
]
}),
new HtmlWebpackPlugin({
filename: 'workflows.html',
template:
'src/features/workflows/presentation/templates/workflows.html.ejs',
chunks: ['workflowManager'],
}),
new webpack.DefinePlugin({
'PRODUCTION': args.mode == 'production',
}),
...getCopyPluginsForOverridenLocales(outputPath),
],
devtool: (args.mode == 'production' ? 'source-map' : 'inline-source-map'),
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json', '.wasm'],
},
module: {
rules: [
{
test: /\.js$/i,
use: [
preprocessorLoader,
],
},
{
test: /\.tsx?$/,
use: [
'ts-loader',
preprocessorLoader,
],
exclude: /node_modules/,
},
{
test: /\.json5$/i,
type: 'json',
parser: {
parse: json5.parse,
},
use: [
preprocessorLoader,
],
},
{
test: /\.s[ac]ss$/i,
oneOf: [
{
resourceQuery: /string/,
use: [
'css-loader',
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
],
},
{
resourceQuery: /asCSSFile/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
],
},
{
use: [
'style-loader',
'css-loader',
{
loader: 'sass-loader',
options: {
// Prefer `dart-sass`
implementation: require('sass'),
},
},
],
},
],
},
]
},
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
format: {
ascii_only:
true, // Due to https://iavm.xyz/b/twpowertools/145#c1
},
},
}),
],
},
};
};
const getCopyPluginsForOverridenLocales = outputPath => {
return localeOverrides.map(l => {
return new CopyWebpackPlugin({
patterns: [
{
from: path.join(__dirname, 'src/static/_locales/' + l.pontoonLocale),
to: path.join(outputPath, '_locales/' + l.webExtLocale),
globOptions: {
ignore: ['**/OWNERS', '**.md'],
}
},
]
});
});
};
const getStylesCopyPatterns = styles => {
return styles.map(s => {
return {
from: path.join(__dirname, s.origin),
to: s.destination,
};
});
}