webpack.conf.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. const { modifyWebpackConfig, shallowMerge, defaultOptions } = require('@gera2ld/plaid');
  2. const { isProd } = require('@gera2ld/plaid/util');
  3. const fs = require('fs');
  4. const webpack = require('webpack');
  5. const WrapperWebpackPlugin = require('wrapper-webpack-plugin');
  6. const HTMLInlineCSSWebpackPlugin = isProd && require('html-inline-css-webpack-plugin').default;
  7. const projectConfig = require('./plaid.conf');
  8. const mergedConfig = shallowMerge(defaultOptions, projectConfig);
  9. const INIT_FUNC_NAME = 'VMInitInjection';
  10. // Copied from gulpfile.js: strip alphabetic suffix
  11. const VM_VER = require('../package.json').version.replace(/-[^.]*/, '');
  12. const pickEnvs = (items) => {
  13. return Object.assign({}, ...items.map(x => ({
  14. [`process.env.${x.key}`]: JSON.stringify(
  15. 'val' in x ? x.val
  16. : process.env[x.key] ?? x.def
  17. ),
  18. })));
  19. };
  20. const definitions = new webpack.DefinePlugin({
  21. ...pickEnvs([
  22. { key: 'DEBUG', def: false },
  23. { key: 'VM_VER', val: VM_VER },
  24. { key: 'SYNC_GOOGLE_CLIENT_ID' },
  25. { key: 'SYNC_GOOGLE_CLIENT_SECRET' },
  26. { key: 'SYNC_ONEDRIVE_CLIENT_ID' },
  27. { key: 'SYNC_ONEDRIVE_CLIENT_SECRET' },
  28. ]),
  29. 'process.env.INIT_FUNC_NAME': JSON.stringify(INIT_FUNC_NAME),
  30. });
  31. const modify = (page, entry, init) => modifyWebpackConfig(
  32. (config) => {
  33. config.node = {
  34. process: false,
  35. setImmediate: false,
  36. };
  37. config.plugins.push(definitions);
  38. if (!entry) init = page;
  39. if (init) init(config);
  40. return config;
  41. }, {
  42. projectConfig: {
  43. ...mergedConfig,
  44. ...entry && { pages: { [page]: { entry }} },
  45. },
  46. },
  47. );
  48. // avoid running webpack bootstrap in a potentially hacked environment
  49. // after documentElement was replaced which triggered reinjection of content scripts
  50. const skipReinjectionHeader = `if (window['${INIT_FUNC_NAME}'] !== 1)`;
  51. const [globalsCommonHeader, globalsInjectedHeader] = [
  52. './src/common/safe-globals.js',
  53. './src/injected/safe-injected-globals.js',
  54. ].map(path =>
  55. require('fs').readFileSync(path, {encoding: 'utf8'}).replace(/export const/g, 'const'));
  56. module.exports = Promise.all([
  57. modify((config) => {
  58. config.output.publicPath = '/';
  59. config.plugins.push(new WrapperWebpackPlugin({
  60. header: `{ ${globalsCommonHeader}`,
  61. footer: `}`,
  62. test: /^(?!injected|public).*\.js$/,
  63. }));
  64. /* Embedding as <style> to ensure uiTheme option doesn't cause FOUC.
  65. * Note that in production build there's no <head> in html but document.head is still
  66. * auto-created per the specification so our styles will be placed correctly anyway. */
  67. if (isProd) config.plugins.push(new HTMLInlineCSSWebpackPlugin({
  68. replace: {
  69. target: '<body>',
  70. position: 'before',
  71. },
  72. }));
  73. config.plugins.push(new class ListBackgroundScripts {
  74. apply(compiler) {
  75. compiler.hooks.afterEmit.tap(this.constructor.name, compilation => {
  76. const dist = compilation.outputOptions.path;
  77. const path = `${dist}/manifest.json`;
  78. const manifest = JSON.parse(fs.readFileSync(path, {encoding: 'utf8'}));
  79. const bgId = 'background/index';
  80. const bgEntry = compilation.entrypoints.get(bgId);
  81. const scripts = bgEntry.chunks.map(c => c.files[0]);
  82. if (`${manifest.background.scripts}` !== `${scripts}`) {
  83. manifest.background.scripts = scripts;
  84. fs.writeFileSync(path,
  85. JSON.stringify(manifest, null, isProd ? 0 : 2),
  86. {encoding: 'utf8'});
  87. }
  88. try {
  89. fs.unlinkSync(`${dist}/${bgId}.html`);
  90. } catch (e) {}
  91. });
  92. }
  93. });
  94. }),
  95. modify('injected', './src/injected', (config) => {
  96. config.plugins.push(
  97. new WrapperWebpackPlugin({
  98. header: `${skipReinjectionHeader} { ${globalsCommonHeader};${globalsInjectedHeader}`,
  99. footer: `}`,
  100. }));
  101. }),
  102. modify('injected-web', './src/injected/web', (config) => {
  103. config.output.libraryTarget = 'commonjs2';
  104. config.plugins.push(
  105. new WrapperWebpackPlugin({
  106. header: `${skipReinjectionHeader}
  107. window['${INIT_FUNC_NAME}'] = function () {
  108. var module = { exports: {} };
  109. ${globalsCommonHeader}
  110. ${globalsInjectedHeader}
  111. `,
  112. footer: `
  113. var exports = module.exports;
  114. return exports.__esModule ? exports['default'] : exports;
  115. };0;`,
  116. }),
  117. );
  118. }),
  119. ]);