forked from extension-js/extension.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
module.ts
99 lines (88 loc) · 3.79 KB
/
module.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import path from 'path'
import type webpack from 'webpack'
import {type IncludeList, type ScriptsPluginInterface} from './types'
import AddScripts from './steps/AddScripts'
import AddStyles from './steps/AddStyles'
import AddHmrAcceptCode from './steps/AddHmrAcceptCode'
import AddPublicPathRuntimeModule from './steps/AddPublicPathRuntimeModule'
import AddDynamicPublicPath from './steps/AddDynamicPublicPath'
import AddQueryParamFromImportedCss from './steps/AddQueryParamFromImportedCss'
/**
* ScriptsPlugin is responsible for handiling all possible JavaScript
* (and CSS, for content_scripts) fields in manifest.json. It also
* supports extra scripts defined via this.include option. These
* extra scripts are added to the compilation and are also HMR
* enabled. They are useful for adding extra scripts to the
* extension runtime, like content_scripts via `scripting`, for example.
*
* Features supported:
* - content_scripts.js - HMR enabled
* - content_scripts.css - HMR enabled
* - background.scripts - HMR enabled
* - service_worker - Reloaded by chrome.runtime.reload()
* - user_scripts.api_scripts - HMR enabled
* - scripts via this.include - HMR enabled
*/
export default class ScriptsPlugin {
public readonly manifestPath: string
public readonly include?: string[]
public readonly exclude?: string[]
constructor(options: ScriptsPluginInterface) {
this.manifestPath = options.manifestPath
this.include = options.include || []
this.exclude = options.exclude || []
}
private parseIncludes(includes: string[]): IncludeList {
if (!includes.length) return {}
return includes.reduce((acc, include) => {
const extname = path.extname(include)
const filename = path.basename(include, extname)
return {
...acc,
[`scripts/${filename}`]: include
}
}, {})
}
public apply(compiler: webpack.Compiler): void {
// 1 - Adds the scripts entries from the manifest file
// and from the extra scripts defined in this.include
// to the compilation.
// In production: Adds the CSS files to the entry points
// along with other content_script files.
// In development: Extracts the content_scripts css files
// from content_scripts and injects them as dynamic imports
// so we can benefit from HMR.
new AddScripts({
manifestPath: this.manifestPath,
includeList: this.parseIncludes(this.include || []),
exclude: this.exclude || []
}).apply(compiler)
if (compiler.options.mode === 'development') {
new AddStyles({
manifestPath: this.manifestPath,
includeList: this.parseIncludes(this.include || []),
exclude: this.exclude || []
}).apply(compiler)
}
// 2 - Ensure scripts are HMR enabled by adding the HMR accept code.
if (compiler.options.mode === 'development') {
AddHmrAcceptCode(compiler, this.manifestPath)
}
// 3 - Fix the issue with the public path not being
// available for content_scripts in the production build.
// See https://github.com/cezaraugusto/extension.js/issues/95
// See https://github.com/cezaraugusto/extension.js/issues/96
if (compiler.options.mode === 'production') {
new AddPublicPathRuntimeModule().apply(compiler)
}
// 4 - Fix the issue where assets imported via content_scripts
// running in the MAIN world could not find the correct public path.
AddDynamicPublicPath(compiler, this.manifestPath)
// 5 - Fix the issue of content_scripts not being able to import
// CSS files via import statements. This loader adds the
// is_content_css_import=true query param to CSS imports in
// content_scripts. This skips the MiniCssExtractPlugin loader
// and allows the CSS to be injected in the DOM via <style> tags.
AddQueryParamFromImportedCss(compiler, this.manifestPath)
}
}