-
-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
93d2478
commit 9dd8ef3
Showing
38 changed files
with
2,998 additions
and
28 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#!/bin/bash | ||
|
||
set -e | ||
|
||
plugin_loader_path() { | ||
local base_folder=$1 | ||
local plugin_folder=$2 | ||
local filename=$3 | ||
echo "$(dirname "$0")/$base_folder/$plugin_folder/steps/$filename" | ||
} | ||
|
||
# Define the files | ||
html_plugin_files=( | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-html' 'ensure-hmr-for-scripts.ts')" | ||
) | ||
|
||
resolve_plugin_files=( | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-resolve' 'resolver-loader.ts')" | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-resolve' 'resolver-module.ts')" | ||
) | ||
|
||
scripts_plugin_files=( | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-scripts' 'inject-content-css-during-dev.ts')" | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-scripts' 'add-hmr-accept-code.ts')" | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-scripts' 'add-dynamic-public-path.ts')" | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-scripts' 'add-query-param-to-imported-css.ts')" | ||
) | ||
|
||
reload_plugin_files=( | ||
"$(plugin_loader_path 'webpack' 'plugin-reload' 'inject-background-runtime-loader.ts')" | ||
) | ||
|
||
# Separate minimum files for esm format | ||
minimum_files=( | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-html' 'minimum-script-file.ts')" | ||
# "$(plugin_loader_path 'plugin-extension' 'feature-scripts' 'minimum-content-file.ts')" | ||
"$(plugin_loader_path 'webpack' 'plugin-reload' 'minimum-background-file.ts')" | ||
) | ||
|
||
tsup() { | ||
local entrypoint=$1 | ||
local format=$2 | ||
echo "node_modules/.bin/tsup-node $entrypoint --format $format --target=node20 --minify" | ||
} | ||
|
||
# Execute tsup command | ||
execute_command() { | ||
local entry=$1 | ||
local format=$2 | ||
command=$(tsup "$entry" "$format") | ||
echo "Executing: $command" | ||
|
||
# Execute the command | ||
$command | ||
|
||
code=$? | ||
echo "[develop] process exited with code $code for entry: $entry" | ||
} | ||
|
||
# Copy required files to dist directory | ||
copy_files_to_dist() { | ||
local files=( | ||
"tailwind.config.js" | ||
"stylelint.config.js" | ||
"commands/dev/types" | ||
"plugin-reload/extensions" | ||
) | ||
for file in "${files[@]}"; do | ||
if [ -e "$file" ]; then | ||
echo "Copying $file to dist/" | ||
cp -r "$file" dist/ | ||
else | ||
echo "File $file does not exist" | ||
fi | ||
done | ||
} | ||
|
||
echo 'Executing commands for HTML plugin files' | ||
for entry in "${html_plugin_files[@]}"; do | ||
execute_command "$entry" "cjs" | ||
done | ||
|
||
echo 'Executing commands for Resolve plugin files' | ||
for entry in "${resolve_plugin_files[@]}"; do | ||
execute_command "$entry" "cjs" | ||
done | ||
|
||
echo 'Executing commands for Scripts plugin files' | ||
for entry in "${scripts_plugin_files[@]}"; do | ||
execute_command "$entry" "cjs" | ||
done | ||
|
||
echo 'Executing commands for Reload plugin files' | ||
for entry in "${reload_plugin_files[@]}"; do | ||
execute_command "$entry" "cjs" | ||
done | ||
|
||
echo 'Executing commands for Minimum files with ESM format' | ||
for entry in "${minimum_files[@]}"; do | ||
execute_command "$entry" "esm" | ||
done | ||
|
||
echo 'Building core module' | ||
execute_command "$(dirname "$0")/module.ts" "cjs" | ||
|
||
echo 'Copying files to dist directory' | ||
copy_files_to_dist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// ██████╗ ███████╗██╗ ██╗███████╗██╗ ██████╗ ██████╗ | ||
// ██╔══██╗██╔════╝██║ ██║██╔════╝██║ ██╔═══██╗██╔══██╗ | ||
// ██║ ██║█████╗ ██║ ██║█████╗ ██║ ██║ ██║██████╔╝ | ||
// ██║ ██║██╔══╝ ╚██╗ ██╔╝██╔══╝ ██║ ██║ ██║██╔═══╝ | ||
// ██████╔╝███████╗ ╚████╔╝ ███████╗███████╗╚██████╔╝██║ | ||
// ╚═════╝ ╚══════╝ ╚═══╝ ╚══════╝╚══════╝ ╚═════╝ ╚═╝ | ||
|
||
import type webpack from 'webpack' | ||
import {type DevOptions} from '../../extensionDev' | ||
import ReactRefreshPlugin from '@pmmmwh/react-refresh-webpack-plugin' | ||
import {isUsingReact} from '../options/react' | ||
import {isUsingPreact} from '../options/preact' | ||
|
||
export default function reloadPlugins(projectPath: string, {mode}: DevOptions) { | ||
return { | ||
constructor: {name: 'ReloadPlugins'}, | ||
apply: (compiler: webpack.Compiler) => { | ||
if (mode !== 'development') return | ||
|
||
if (isUsingReact(projectPath) || isUsingPreact(projectPath)) { | ||
new ReactRefreshPlugin().apply(compiler) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import fs from 'fs'; | ||
import webpack, { type Compilation } from 'webpack'; | ||
import * as messages from './messages'; | ||
import { type FilepathList } from '../types'; | ||
|
||
export function manifestNotFoundError(compilation: Compilation) { | ||
const errorMessage = messages.manifestMissingError(); | ||
|
||
compilation.errors.push(new webpack.WebpackError(errorMessage)); | ||
} | ||
|
||
export function entryNotFoundWarn( | ||
compilation: Compilation, | ||
feature: string, | ||
htmlFilePath: string, | ||
) { | ||
const errorMessage = messages.manifestFieldError(feature, htmlFilePath); | ||
|
||
compilation.warnings.push(new webpack.WebpackError(errorMessage)); | ||
} | ||
|
||
export function fileNotFoundWarn( | ||
compilation: Compilation, | ||
manifestPath: string, | ||
htmlFilePath: string, | ||
filePath: string, | ||
) { | ||
const errorMessage = messages.fileNotFound( | ||
manifestPath, | ||
htmlFilePath, | ||
filePath, | ||
); | ||
|
||
compilation.warnings.push(new webpack.WebpackError(errorMessage)); | ||
} | ||
|
||
export function serverStartRequiredError(compilation: Compilation) { | ||
const errorMessage = messages.serverRestartRequiredFromManifest(); | ||
|
||
compilation.errors.push(new webpack.WebpackError(errorMessage)); | ||
} | ||
|
||
export function noValidFolderError(compilation: webpack.Compilation) { | ||
const hintMessage2 = `or remove the \`default_locale\` field from your \`manifest.json\` file.`; | ||
const hintMessage = `Ensure the \`_locales\` folder is valid and available at the root of your project. ${hintMessage2}`; | ||
const errorMessage = `Default locale was specified, but \`_locales\` subtree is missing. ${hintMessage}`; | ||
|
||
compilation.errors.push( | ||
new webpack.WebpackError(`[_locales]: ${errorMessage}`), | ||
); | ||
} | ||
|
||
export function manifestInvalidError( | ||
compilation: webpack.Compilation, | ||
error: NodeJS.ErrnoException, | ||
) { | ||
compilation.errors.push( | ||
new webpack.WebpackError(messages.manifestInvalidError(error)), | ||
); | ||
} | ||
|
||
export function handleHtmlErrors( | ||
compilation: Compilation, | ||
includesList: FilepathList, | ||
WebpackError: typeof webpack.WebpackError, | ||
) { | ||
const htmlFields = includesList; | ||
|
||
for (const [field, value] of Object.entries(htmlFields)) { | ||
if (value) { | ||
const fieldError = messages.manifestFieldError(field, value as string); | ||
|
||
if (!fs.existsSync(value as string)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
export function handleIconsErrors( | ||
compilation: Compilation, | ||
includesList: FilepathList, | ||
WebpackError: typeof webpack.WebpackError, | ||
) { | ||
const iconsFields = includesList; | ||
|
||
for (const [field, value] of Object.entries(iconsFields)) { | ||
if (value) { | ||
if (typeof value === 'string') { | ||
const fieldError = messages.manifestFieldError(field, value); | ||
|
||
if (!fs.existsSync(value)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
|
||
if (value != null && value.constructor.name === 'Object') { | ||
const icon = value as { light?: string; dark?: string }; | ||
|
||
if (icon.light) { | ||
const fieldError = messages.manifestFieldError(field, icon.light); | ||
|
||
if (!fs.existsSync(icon.dark!)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
|
||
if (icon.dark) { | ||
const fieldError = messages.manifestFieldError(field, icon.dark); | ||
|
||
if (!fs.existsSync(icon.dark)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
|
||
if (Array.isArray(value)) { | ||
for (const icon of value) { | ||
const fieldError = messages.manifestFieldError(field, icon as string); | ||
|
||
if (typeof icon === 'string') { | ||
if (!fs.existsSync(icon)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
export function handleJsonErrors( | ||
compilation: Compilation, | ||
includesList: FilepathList, | ||
WebpackError: typeof webpack.WebpackError, | ||
) { | ||
const jsonFields = includesList; | ||
|
||
for (const [field, value] of Object.entries(jsonFields)) { | ||
if (value) { | ||
const valueArr: string[] = Array.isArray(value) ? value : [value]; | ||
|
||
for (const json of valueArr) { | ||
const fieldError = messages.manifestFieldError(field, json); | ||
|
||
if (!fs.existsSync(json)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
export function handleScriptsErrors( | ||
compilation: Compilation, | ||
includesList: FilepathList, | ||
WebpackError: typeof webpack.WebpackError, | ||
) { | ||
const scriptsFields = includesList; | ||
|
||
for (const [field, value] of Object.entries(scriptsFields)) { | ||
if (value) { | ||
const valueArr = Array.isArray(value) ? value : [value]; | ||
|
||
for (const script of valueArr) { | ||
if (field.startsWith('content_scripts')) { | ||
const [featureName, index] = field.split('-'); | ||
const prettyFeature = `${featureName} (index ${index})`; | ||
const fieldError = messages.manifestFieldError(prettyFeature, script); | ||
|
||
if (!fs.existsSync(script)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} else { | ||
const fieldError = messages.manifestFieldError(field, script); | ||
|
||
if (!fs.existsSync(script)) { | ||
compilation.errors.push(new WebpackError(fieldError)); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import path from 'path'; | ||
import goGitIt from 'go-git-it'; | ||
import { blue, green, white, bold, underline } from '@colors/colors/safe'; | ||
import downloadAndExtractZip from '../commands/dev/extract-from-zip'; | ||
|
||
const isUrl = (url: string) => { | ||
try { | ||
// eslint-disable-next-line no-new | ||
new URL(url); | ||
return true; | ||
} catch (e) { | ||
return false; | ||
} | ||
}; | ||
|
||
async function importUrlSourceFromGithub( | ||
pathOrRemoteUrl: string, | ||
text: string, | ||
) { | ||
await goGitIt(pathOrRemoteUrl, process.cwd(), text); | ||
|
||
return path.resolve(process.cwd(), path.basename(pathOrRemoteUrl)); | ||
} | ||
|
||
async function importUrlSourceFromZip(pathOrRemoteUrl: string) { | ||
await downloadAndExtractZip(pathOrRemoteUrl, process.cwd()); | ||
// remove all query params from url | ||
pathOrRemoteUrl = pathOrRemoteUrl.split('?')[0]; | ||
|
||
return path.resolve(process.cwd(), path.basename(pathOrRemoteUrl)); | ||
} | ||
|
||
export async function getProjectPath(pathOrRemoteUrl: string | undefined) { | ||
if (!pathOrRemoteUrl) { | ||
return process.cwd(); | ||
} | ||
|
||
if (isUrl(pathOrRemoteUrl)) { | ||
const url = new URL(pathOrRemoteUrl); | ||
|
||
if (url.protocol.startsWith('http')) { | ||
if (url.origin !== 'https://github.com') { | ||
const urlSource = await importUrlSourceFromZip(pathOrRemoteUrl); | ||
|
||
return urlSource; | ||
} | ||
|
||
const urlData = url.pathname.split('/'); | ||
const owner = urlData.slice(1, 3)[0]; | ||
const project = urlData.slice(1, 3)[1]; | ||
const projectName = path.basename(url.pathname); | ||
console.log( | ||
`🧩 ${bold(`Extension.js`)} ${green(`►►►`)} Fetching data from ${blue( | ||
underline(`https://github.com/${owner}/${project}`), | ||
)}`, | ||
); | ||
const downloadingText = `🧩 ${bold(`Extension.js`)} ${green( | ||
`►►►`, | ||
)} Downloading ${bold(projectName)}...`; | ||
const urlSource = await importUrlSourceFromGithub( | ||
pathOrRemoteUrl, | ||
downloadingText, | ||
); | ||
console.log( | ||
`🧩 ${bold(`Extension.js`)} ${green( | ||
`►►►`, | ||
)} Creating a new browser extension in ${white( | ||
underline(`${process.cwd()}/${projectName}`), | ||
)}`, | ||
); | ||
|
||
return urlSource; | ||
} | ||
} | ||
|
||
return path.resolve(process.cwd(), pathOrRemoteUrl); | ||
} |
Oops, something went wrong.