Skip to content

Commit

Permalink
Use detached ReloadPlugin
Browse files Browse the repository at this point in the history
  • Loading branch information
cezaraugusto committed Jul 20, 2024
1 parent 93d2478 commit 9dd8ef3
Show file tree
Hide file tree
Showing 38 changed files with 2,998 additions and 28 deletions.
107 changes: 107 additions & 0 deletions programs/develop/install-scripts.sh
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
25 changes: 25 additions & 0 deletions programs/develop/webpack/_plugin-reload/index.ts
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)
}
}
}
}
184 changes: 184 additions & 0 deletions programs/develop/webpack/lib/errors.ts
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));
}
}
}
}
}
}
77 changes: 77 additions & 0 deletions programs/develop/webpack/lib/get-project-path.ts
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);
}
Loading

0 comments on commit 9dd8ef3

Please sign in to comment.