webpack.config.js
Rama master · réplica de lectura del repositorio original.
const path = require('path');
const fs = require('fs');
const CopyPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const sharp = require('sharp');
const { mergeWith } = require('lodash');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
console.log('Webpack started');
const package = require('./package.json');
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development';
const isProduction = mode === 'production';
const target = process.env.EXT_TARGET;
const devtool = isProduction ? undefined : 'inline-source-map';
const isFastBuild = !isProduction && process.env.FAST_BUILD === 'on';
const isBundleAnalyzingEnabled = !isProduction || Boolean(process.env.DEBUG);
const targetsList = ['firefox', 'firefox-standalone', 'chromium', 'chrome'];
if (targetsList.indexOf(target) === -1) {
throw new Error(`Invalid target "${target}" in EXT_TARGET`);
}
const devPrefix = isProduction ? '' : 'dev/';
const outDir = `build/${devPrefix}${target}`;
const outputPath = path.join(__dirname, outDir);
// https://lodash.com/docs/4.17.15#mergeWith
function mergeCustomizer(objValue, srcValue) {
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
return objValue.concat(srcValue);
}
}
console.log('WebpackConfig', {
mode,
target,
outputPath,
isFastBuild,
});
const offscreenDocuments = ['main', 'worker', 'translator'];
const pages = ['popup', 'options', 'dictionary', 'history'];
module.exports = {
mode,
devtool,
target: 'web',
stats: {
colors: true,
reasons: true,
hash: true,
version: true,
timings: true,
chunks: true,
chunkModules: true,
cached: true,
cachedAssets: true,
},
resolve: {
extensions: ['.js', '.ts', '.tsx'],
},
entry: {
'background-script': './src/background-script.ts',
contentscript: './src/contentscript.tsx',
...Object.fromEntries(
offscreenDocuments.map((name) => [
`offscreen-documents/${name}/${name}`,
`./src/offscreen-documents/${name}/${name}.ts`,
]),
),
...Object.fromEntries(
pages.map((name) => [
`pages/${name}/${name}`,
`./src/pages/${name}/${name}.tsx`,
]),
),
},
output: {
path: outputPath,
},
plugins: [
new MiniCssExtractPlugin({}),
...(isBundleAnalyzingEnabled
? [
new BundleAnalyzerPlugin({
analyzerPort: 8888 + 10 + targetsList.indexOf(target),
}),
]
: []),
new CopyPlugin({
patterns: [
// Manifest
{
from: `./manifests/manifest.json`,
to: path.join(outputPath, 'manifest.json'),
transform(content) {
const rawManifest = content.toString();
let manifest = JSON.parse(rawManifest);
// Patch manifest with data from target manifest
const targetManifestPath = path.join(
__dirname,
'manifests',
target + '.json',
);
if (
target &&
fs.existsSync(targetManifestPath) &&
fs.lstatSync(targetManifestPath).isFile()
) {
const rawTargetManifest = fs
.readFileSync(targetManifestPath)
.toString();
const targetManifest = JSON.parse(rawTargetManifest);
manifest = mergeWith(
manifest,
targetManifest,
mergeCustomizer,
);
}
// Patch manifest with production overrides
const productionOverridesMap = {
'firefox-standalone': {
// eslint-disable-next-line camelcase
browser_specific_settings: {
gecko: {
id: '{e3fc2d33-09fc-4fe8-9331-d0a464698035}',
},
},
},
};
if (isProduction && target in productionOverridesMap) {
const productionOverrides = productionOverridesMap[target];
manifest = mergeWith(
manifest,
productionOverrides,
mergeCustomizer,
);
}
// Set version
manifest.version = package.version;
// Stringify with prettifying and convert to buffer
const modifiedManifest = JSON.stringify(manifest, null, '\t');
return Buffer.from(modifiedManifest);
},
},
// HTML pages
...[
...offscreenDocuments.map(
(name) => `offscreen-documents/${name}/${name}.html`,
),
...pages.map((name) => `pages/${name}/${name}.html`),
].map((file) => ({
from: './src/' + file,
to: path.join(outputPath, file),
})),
// Resources & locales
{
from: './src/_locales',
to: path.join(outputPath, '_locales'),
},
// Offline translator
{
from: 'thirdparty/bergamot/build/*.{js,wasm}',
to: path.join(outputPath, 'thirdparty/bergamot/[name][ext]'),
},
// Serve static files
...['logo.svg'].map((filename) => ({
from: './src/res/' + filename,
to: path.join(outputPath, 'static', filename),
})),
// Convert svg to png files for use as addon logotypes (chromium is not support svg logotypes)
...['logo.svg'].map((file) => ({
from: './src/res/' + file,
to: path.join(outputPath, 'static', file.replace(/\.svg$/, '.png')),
transform(content) {
return sharp(content).resize(128, 128).toBuffer();
},
})),
],
}),
],
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'ts-loader',
options: {
onlyCompileBundledFiles: true,
allowTsInNodeModules: true,
transpileOnly: isFastBuild,
},
},
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: [
[
'postcss-rem-to-pixel',
{
rootValue: 16,
unitPrecision: 5,
propList: ['*'],
selectorBlackList: [],
replace: true,
mediaQuery: false,
minUnitValue: 0,
},
],
],
},
},
},
],
},
{
test: /\.ttf$/,
loader: 'file-loader',
options: {
publicPath: '/',
},
},
{
test: /\.svg$/,
use: ['@svgr/webpack'],
},
{
test: /\.txt$/i,
type: 'asset/source',
},
],
},
};