@ -49,6 +49,7 @@ const metamaskrc = require('rc')('metamask', {
const { streamFlatMap } = require ( '../stream-flat-map' ) ;
const { BuildType } = require ( '../lib/build-type' ) ;
const { BUILD _TARGETS } = require ( './constants' ) ;
const {
createTask ,
@ -73,6 +74,32 @@ const ENVIRONMENT = {
TESTING : 'testing' ,
} ;
/ * *
* Returns whether the current build is a development build or not .
*
* @ param { BUILD _TARGETS } buildTarget - The current build target .
* @ returns Whether the current build is a development build .
* /
function isDevBuild ( buildTarget ) {
return (
buildTarget === BUILD _TARGETS . DEVELOPMENT ||
buildTarget === BUILD _TARGETS . E2E _TEST _DEV
) ;
}
/ * *
* Returns whether the current build is an e2e test build or not .
*
* @ param { BUILD _TARGETS } buildTarget - The current build target .
* @ returns Whether the current build is an e2e test build .
* /
function isTestBuild ( buildTarget ) {
return (
buildTarget === BUILD _TARGETS . E2E _TEST ||
buildTarget === BUILD _TARGETS . E2E _TEST _DEV
) ;
}
/ * *
* Get a value from the configuration , and confirm that it is set .
*
@ -94,7 +121,7 @@ function getConfigValue(key) {
* @ param { object } options - The Infura project ID options .
* @ param { BuildType } options . buildType - The current build type .
* @ param { ENVIRONMENT [ keyof ENVIRONMENT ] } options . environment - The build environment .
* @ param { boolean } options . testing - Whether the current build is a test build or not .
* @ param { boolean } options . testing - Whether this is a test build or not .
* @ returns { string } The Infura project ID .
* /
function getInfuraProjectId ( { buildType , environment , testing } ) {
@ -223,21 +250,24 @@ function createScriptTasks({
const core = {
// dev tasks (live reload)
dev : createTasksForScriptBundles ( {
buildTarget : BUILD _TARGETS . DEVELOPMENT ,
taskPrefix : 'scripts:core:dev' ,
devMode : true ,
} ) ,
testDev : createTasksForScriptBundles ( {
taskPrefix : 'scripts:core:test-live' ,
devMode : true ,
testing : true ,
// production
prod : createTasksForScriptBundles ( {
buildTarget : BUILD _TARGETS . PRODUCTION ,
taskPrefix : 'scripts:core:prod' ,
} ) ,
// built for CI tests
test : createTasksForScriptBundles ( {
buildTarget : BUILD _TARGETS . E2E _TEST ,
taskPrefix : 'scripts:core:test' ,
testing : true ,
} ) ,
// production
prod : createTasksForScriptBundles ( { taskPrefix : 'scripts:core:prod' } ) ,
// built for CI test debugging
testDev : createTasksForScriptBundles ( {
buildTarget : BUILD _TARGETS . E2E _TEST _DEV ,
taskPrefix : 'scripts:core:test-live' ,
} ) ,
} ;
// high level tasks
@ -251,26 +281,20 @@ function createScriptTasks({
* parallel for a single type of build ( e . g . dev , testing , production ) .
*
* @ param { object } options - The build options .
* @ param { BUILD _TARGETS } options . buildTarget - The build target that these
* JavaScript modules are intended for .
* @ param { string } options . taskPrefix - The prefix to use for the name of
* each defined task .
* @ param { boolean } [ options . devMode ] - Whether the build is being used for
* development .
* @ param { boolean } [ options . testing ] - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* /
function createTasksForScriptBundles ( {
taskPrefix ,
devMode = false ,
testing = false ,
} ) {
function createTasksForScriptBundles ( { buildTarget , taskPrefix } ) {
const standardEntryPoints = [ 'background' , 'ui' , 'content-script' ] ;
const standardSubtask = createTask (
` ${ taskPrefix } :standardEntryPoints ` ,
createFactoredBuild ( {
applyLavaMoat ,
browserPlatforms ,
buildTarget ,
buildType ,
devMode ,
entryFiles : standardEntryPoints . map ( ( label ) => {
if ( label === 'content-script' ) {
return './app/vendor/trezor/content-script.js' ;
@ -280,7 +304,6 @@ function createScriptTasks({
ignoredFiles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) ,
) ;
@ -289,24 +312,24 @@ function createScriptTasks({
// because inpage bundle result is included inside contentscript
const contentscriptSubtask = createTask (
` ${ taskPrefix } :contentscript ` ,
createContentscriptBundle ( { devMode , testing } ) ,
createContentscriptBundle ( { buildTarget } ) ,
) ;
// this can run whenever
const disableConsoleSubtask = createTask (
` ${ taskPrefix } :disable-console ` ,
createDisableConsoleBundle ( { devMode , testing } ) ,
createDisableConsoleBundle ( { buildTarget } ) ,
) ;
// this can run whenever
const installSentrySubtask = createTask (
` ${ taskPrefix } :sentry ` ,
createSentryBundle ( { devMode , testing } ) ,
createSentryBundle ( { buildTarget } ) ,
) ;
// task for initiating browser livereload
const initiateLiveReload = async ( ) => {
if ( devMode ) {
if ( isDevBuild ( buildTarget ) ) {
// trigger live reload when the bundles are updated
// this is not ideal, but overcomes the limitations:
// - run from the main process (not child process tasks)
@ -343,23 +366,19 @@ function createScriptTasks({
* Create a bundle for the "disable-console" module .
*
* @ param { object } options - The build options .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ returns { Function } A function that creates the bundle .
* /
function createDisableConsoleBundle ( { devMode , testing } ) {
function createDisableConsoleBundle ( { buildTarget } ) {
const label = 'disable-console' ;
return createNormalBundle ( {
browserPlatforms ,
buildTarget ,
buildType ,
destFilepath : ` ${ label } .js ` ,
devMode ,
entryFilepath : ` ./app/scripts/ ${ label } .js ` ,
ignoredFiles ,
label ,
testing ,
policyOnly ,
shouldLintFenceFiles ,
version ,
@ -370,23 +389,19 @@ function createScriptTasks({
* Create a bundle for the "sentry-install" module .
*
* @ param { object } options - The build options .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ returns { Function } A function that creates the bundle .
* /
function createSentryBundle ( { devMode , testing } ) {
function createSentryBundle ( { buildTarget } ) {
const label = 'sentry-install' ;
return createNormalBundle ( {
browserPlatforms ,
buildTarget ,
buildType ,
destFilepath : ` ${ label } .js ` ,
devMode ,
entryFilepath : ` ./app/scripts/ ${ label } .js ` ,
ignoredFiles ,
label ,
testing ,
policyOnly ,
shouldLintFenceFiles ,
version ,
@ -399,40 +414,35 @@ function createScriptTasks({
* module .
*
* @ param { object } options - The build options .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ returns { Function } A function that creates the bundles .
* /
function createContentscriptBundle ( { devMode , testing } ) {
function createContentscriptBundle ( { buildTarget } ) {
const inpage = 'inpage' ;
const contentscript = 'contentscript' ;
return composeSeries (
createNormalBundle ( {
buildTarget ,
buildType ,
browserPlatforms ,
destFilepath : ` ${ inpage } .js ` ,
devMode ,
entryFilepath : ` ./app/scripts/ ${ inpage } .js ` ,
label : inpage ,
ignoredFiles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) ,
createNormalBundle ( {
buildTarget ,
buildType ,
browserPlatforms ,
destFilepath : ` ${ contentscript } .js ` ,
devMode ,
entryFilepath : ` ./app/scripts/ ${ contentscript } .js ` ,
label : contentscript ,
ignoredFiles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) ,
) ;
@ -451,10 +461,9 @@ function createScriptTasks({
* LavaMoat at runtime or not .
* @ param { string [ ] } options . browserPlatforms - A list of browser platforms to
* build bundles for .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ param { BuildType } options . buildType - The current build type ( e . g . "main" ,
* "flask" , etc . ) .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { string [ ] | null } options . ignoredFiles - A list of files to exclude
* from the current build .
* @ param { string [ ] } options . jsBundles - A list of JavaScript bundles to be
@ -464,21 +473,18 @@ function createScriptTasks({
* LavaMoat policy itself .
* @ param { boolean } options . shouldLintFenceFiles - Whether files with code
* fences should be linted after fences have been removed .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { string } options . version - The current version of the extension .
* @ returns { Function } A function that creates the set of bundles .
* /
async function createManifestV3AppInitializationBundle ( {
applyLavaMoat ,
browserPlatforms ,
buildTarget ,
buildType ,
devMode ,
ignoredFiles ,
jsBundles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) {
const label = 'app-init' ;
@ -502,14 +508,13 @@ async function createManifestV3AppInitializationBundle({
await createNormalBundle ( {
browserPlatforms : mv3BrowserPlatforms ,
buildTarget ,
buildType ,
destFilepath : 'app-init.js' ,
devMode ,
entryFilepath : './app/scripts/app-init.js' ,
extraEnvironmentVariables ,
ignoredFiles ,
label ,
testing ,
policyOnly ,
shouldLintFenceFiles ,
version ,
@ -517,7 +522,7 @@ async function createManifestV3AppInitializationBundle({
// Code below is used to set statsMode to true when testing in MV3
// This is used to capture module initialisation stats using lavamoat.
if ( testing ) {
if ( isTestBuild ( buildTarget ) ) {
const content = readFileSync ( './dist/chrome/runtime-lavamoat.js' , 'utf8' ) ;
const fileOutput = content . replace ( 'statsMode = false' , 'statsMode = true' ) ;
writeFileSync ( './dist/chrome/runtime-lavamoat.js' , fileOutput ) ;
@ -541,10 +546,9 @@ async function createManifestV3AppInitializationBundle({
* LavaMoat at runtime or not .
* @ param { string [ ] } options . browserPlatforms - A list of browser platforms to
* build bundles for .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ param { BuildType } options . buildType - The current build type ( e . g . "main" ,
* "flask" , etc . ) .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { string [ ] } options . entryFiles - A list of entry point file paths ,
* relative to the repository root directory .
* @ param { string [ ] | null } options . ignoredFiles - A list of files to exclude
@ -554,21 +558,18 @@ async function createManifestV3AppInitializationBundle({
* LavaMoat policy itself .
* @ param { boolean } options . shouldLintFenceFiles - Whether files with code
* fences should be linted after fences have been removed .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { string } options . version - The current version of the extension .
* @ returns { Function } A function that creates the set of bundles .
* /
function createFactoredBuild ( {
applyLavaMoat ,
browserPlatforms ,
buildTarget ,
buildType ,
devMode ,
entryFiles ,
ignoredFiles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) {
return async function ( ) {
@ -578,25 +579,23 @@ function createFactoredBuild({
const { bundlerOpts , events } = buildConfiguration ;
// devMode options
const reloadOnChange = Boolean ( devMode ) ;
const minify = Boolean ( devMode ) === false ;
const reloadOnChange = isDevBuild ( buildTarget ) ;
const minify = ! isDevBuild ( buildTarget ) ;
const envVars = getEnvironmentVariables ( {
buildTarget ,
buildType ,
devMode ,
testing ,
version ,
} ) ;
setupBundlerDefaults ( buildConfiguration , {
buildTarget ,
buildType ,
devMode ,
envVars ,
ignoredFiles ,
policyOnly ,
minify ,
reloadOnChange ,
shouldLintFenceFiles ,
testing ,
} ) ;
// set bundle entries
@ -725,13 +724,12 @@ function createFactoredBuild({
await createManifestV3AppInitializationBundle ( {
applyLavaMoat ,
browserPlatforms ,
buildTarget ,
buildType ,
devMode ,
ignoredFiles ,
jsBundles ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) ;
}
@ -766,12 +764,11 @@ function createFactoredBuild({
* @ param { object } options - Build options .
* @ param { string [ ] } options . browserPlatforms - A list of browser platforms to
* build the bundle for .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ param { BuildType } options . buildType - The current build type ( e . g . "main" ,
* "flask" , etc . ) .
* @ param { string } options . destFilepath - The file path the bundle should be
* written to .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { string [ ] } options . entryFilepath - The entry point file path ,
* relative to the repository root directory .
* @ param { Record < string , unknown > } options . extraEnvironmentVariables - Extra
@ -785,23 +782,20 @@ function createFactoredBuild({
* LavaMoat policy itself .
* @ param { boolean } options . shouldLintFenceFiles - Whether files with code
* fences should be linted after fences have been removed .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { string } options . version - The current version of the extension .
* @ returns { Function } A function that creates the bundle .
* /
function createNormalBundle ( {
browserPlatforms ,
buildTarget ,
buildType ,
destFilepath ,
devMode ,
entryFilepath ,
extraEnvironmentVariables ,
ignoredFiles ,
label ,
policyOnly ,
shouldLintFenceFiles ,
testing ,
version ,
} ) {
return async function ( ) {
@ -811,28 +805,26 @@ function createNormalBundle({
const { bundlerOpts , events } = buildConfiguration ;
// devMode options
const devMode = isDevBuild ( buildTarget ) ;
const reloadOnChange = Boolean ( devMode ) ;
const minify = Boolean ( devMode ) === false ;
const envVars = {
... getEnvironmentVariables ( {
buildTarget ,
buildType ,
devMode ,
testing ,
version ,
} ) ,
... extraEnvironmentVariables ,
} ;
setupBundlerDefaults ( buildConfiguration , {
buildType ,
devMode ,
envVars ,
ignoredFiles ,
policyOnly ,
minify ,
reloadOnChange ,
shouldLintFenceFiles ,
testing ,
} ) ;
// set bundle entries
@ -874,15 +866,14 @@ function createBuildConfiguration() {
function setupBundlerDefaults (
buildConfiguration ,
{
buildTarget ,
buildType ,
devMode ,
envVars ,
ignoredFiles ,
policyOnly ,
minify ,
reloadOnChange ,
shouldLintFenceFiles ,
testing ,
} ,
) {
const { bundlerOpts } = buildConfiguration ;
@ -905,13 +896,13 @@ function setupBundlerDefaults(
// Look for TypeScript files when walking the dependency tree
extensions ,
// Use entryFilepath for moduleIds, easier to determine origin file
fullPaths : devMode || testing ,
fullPaths : isDevBuild ( buildTarget ) || isTestBuild ( buildTarget ) ,
// For sourcemaps
debug : true ,
} ) ;
// Ensure react-devtools are not included in non- dev builds
if ( ! devMode || testing ) {
// Ensure react-devtools is only included in dev builds
if ( buildTarget !== BUILD _TARGETS . DEVELOPMENT ) {
bundlerOpts . manualIgnore . push ( 'react-devtools' ) ;
bundlerOpts . manualIgnore . push ( 'remote-redux-devtools' ) ;
}
@ -937,7 +928,7 @@ function setupBundlerDefaults(
}
// Setup source maps
setupSourcemaps ( buildConfiguration , { devMode } ) ;
setupSourcemaps ( buildConfiguration , { buildTarget } ) ;
}
}
@ -991,7 +982,7 @@ function setupMinification(buildConfiguration) {
} ) ;
}
function setupSourcemaps ( buildConfiguration , { devMode } ) {
function setupSourcemaps ( buildConfiguration , { buildTarget } ) {
const { events } = buildConfiguration ;
events . on ( 'configurePipeline' , ( { pipeline } ) => {
pipeline . get ( 'sourcemaps:init' ) . push ( sourcemaps . init ( { loadMaps : true } ) ) ;
@ -1000,7 +991,7 @@ function setupSourcemaps(buildConfiguration, { devMode }) {
// Use inline source maps for development due to Chrome DevTools bug
// https://bugs.chromium.org/p/chromium/issues/detail?id=931675
. push (
devMode
isDevBuild ( buildTarget )
? sourcemaps . write ( )
: sourcemaps . write ( '../sourcemaps' , { addComment : false } ) ,
) ;
@ -1071,49 +1062,53 @@ async function createBundle(buildConfiguration, { reloadOnChange }) {
* Get environment variables to inject in the current build .
*
* @ param { object } options - Build options .
* @ param { BUILD _TARGETS } options . buildTarget - The current build target .
* @ param { BuildType } options . buildType - The current build type ( e . g . "main" ,
* "flask" , etc . ) .
* @ param { boolean } options . devMode - Whether the build is being used for
* development .
* @ param { boolean } options . testing - Whether the build is intended for
* running end - to - end ( e2e ) tests .
* @ param { string } options . version - The current version of the extension .
* @ returns { object } A map of environment variables to inject .
* /
function getEnvironmentVariables ( { buildType , devMode , testing , version } ) {
const environment = getEnvironment ( { devMode , testing } ) ;
function getEnvironmentVariables ( { buildTarget , buildType , version } ) {
const environment = getEnvironment ( { buildTarget } ) ;
if ( environment === ENVIRONMENT . PRODUCTION && ! process . env . SENTRY _DSN ) {
throw new Error ( 'Missing SENTRY_DSN environment variable' ) ;
}
const devMode = isDevBuild ( buildTarget ) ;
const testing = isTestBuild ( buildTarget ) ;
return {
COLLECTIBLES _V1 : metamaskrc . COLLECTIBLES _V1 === '1' ,
CONF : devMode ? metamaskrc : { } ,
IN _TEST : testing ,
INFURA _PROJECT _ID : getInfuraProjectId ( {
buildType ,
environment ,
testing ,
} ) ,
METAMASK _DEBUG : devMode ,
METAMASK _ENVIRONMENT : environment ,
METAMASK _VERSION : version ,
METAMASK _BUILD _TYPE : buildType ,
NODE _ENV : devMode ? ENVIRONMENT . DEVELOPMENT : ENVIRONMENT . PRODUCTION ,
IN _TEST : testing ,
ONBOARDING _V2 : metamaskrc . ONBOARDING _V2 === '1' ,
PHISHING _WARNING _PAGE _URL : getPhishingWarningPageUrl ( { testing } ) ,
PUBNUB _SUB _KEY : process . env . PUBNUB _SUB _KEY || '' ,
PUBNUB _PUB _KEY : process . env . PUBNUB _PUB _KEY || '' ,
CONF : devMode ? metamaskrc : { } ,
SENTRY _DSN : process . env . SENTRY _DSN ,
SENTRY _DSN _DEV : metamaskrc . SENTRY _DSN _DEV ,
INFURA _PROJECT _ID : getInfuraProjectId ( { buildType , environment , testing } ) ,
PUBNUB _SUB _KEY : process . env . PUBNUB _SUB _KEY || '' ,
SEGMENT _HOST : metamaskrc . SEGMENT _HOST ,
SEGMENT _WRITE _KEY : getSegmentWriteKey ( { buildType , environment } ) ,
SENTRY _DSN : process . env . SENTRY _DSN ,
SENTRY _DSN _DEV : metamaskrc . SENTRY _DSN _DEV ,
SIWE _V1 : metamaskrc . SIWE _V1 === '1' ,
SWAPS _USE _DEV _APIS : process . env . SWAPS _USE _DEV _APIS === '1' ,
ONBOARDING _V2 : metamaskrc . ONBOARDING _V2 === '1' ,
COLLECTIBLES _V1 : metamaskrc . COLLECTIBLES _V1 === '1' ,
TOKEN _DETECTION _V2 : metamaskrc . TOKEN _DETECTION _V2 === '1' ,
} ;
}
function getEnvironment ( { devMode , testing } ) {
function getEnvironment ( { buildTarget } ) {
// get environment slug
if ( devMode ) {
if ( isDevBuild ( buildTarget ) ) {
return ENVIRONMENT . DEVELOPMENT ;
} else if ( testing ) {
} else if ( isTestBuild ( buildTarget ) ) {
return ENVIRONMENT . TESTING ;
} else if ( process . env . CIRCLE _BRANCH === 'master' ) {
return ENVIRONMENT . PRODUCTION ;