diff --git a/apps/aztec-compiler/.eslintrc b/apps/aztec-compiler/.eslintrc new file mode 100644 index 00000000000..2d85f9fa667 --- /dev/null +++ b/apps/aztec-compiler/.eslintrc @@ -0,0 +1,3 @@ +{ + "extends": "../../.eslintrc.json", +} \ No newline at end of file diff --git a/apps/aztec-compiler/project.json b/apps/aztec-compiler/project.json new file mode 100644 index 00000000000..a07642b07ba --- /dev/null +++ b/apps/aztec-compiler/project.json @@ -0,0 +1,67 @@ +{ + "name": "aztec-compiler", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "apps/aztec-compiler/src", + "projectType": "application", + "implicitDependencies": [], + "targets": { + "build": { + "executor": "@nrwl/webpack:webpack", + "outputs": ["{options.outputPath}"], + "defaultConfiguration": "development", + "options": { + "compiler": "babel", + "outputPath": "dist/apps/aztec-compiler", + "index": "apps/aztec-compiler/src/index.html", + "baseHref": "./", + "main": "apps/aztec-compiler/src/main.tsx", + "polyfills": "apps/aztec-compiler/src/polyfills.ts", + "tsConfig": "apps/aztec-compiler/tsconfig.app.json", + "assets": ["apps/aztec-compiler/src/profile.json"], + "styles": ["apps/aztec-compiler/src/css/app.css"], + "scripts": [], + "webpackConfig": "apps/aztec-compiler/webpack.config.js" + }, + "configurations": { + "development": { + }, + "production": { + "fileReplacements": [ + { + "replace": "apps/aztec-compiler/src/environments/environment.ts", + "with": "apps/aztec-compiler/src/environments/environment.prod.ts" + } + ] + } + } + }, + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["apps/aztec-compiler/**/*.ts"], + "eslintConfig": "apps/aztec-compiler/.eslintrc" + } + }, + "serve": { + "executor": "@nrwl/webpack:dev-server", + "defaultConfiguration": "development", + "options": { + "buildTarget": "aztec-compiler:build", + "hmr": true, + "baseHref": "/" + }, + "configurations": { + "development": { + "buildTarget": "aztec-compiler:build:development", + "port": 2023 + }, + "production": { + "buildTarget": "aztec-compiler:build:production" + } + } + } + }, + "tags": [] + } + \ No newline at end of file diff --git a/apps/aztec-compiler/src/app/app.tsx b/apps/aztec-compiler/src/app/app.tsx new file mode 100644 index 00000000000..e51a0a6b1d5 --- /dev/null +++ b/apps/aztec-compiler/src/app/app.tsx @@ -0,0 +1,27 @@ +import { useReducer } from 'react' +import { IntlProvider } from 'react-intl' +import { RenderIf } from '@remix-ui/helper' +import { Compile } from './components/Compile' +import { pluginReducer, initialState } from './reducers/state' +import { AztecPluginClient } from './services/aztecPluginClient' +import { PluginContext } from './contexts/pluginContext' + +const plugin = new AztecPluginClient() + +function App() { + const [state, dispatch] = useReducer(pluginReducer, initialState) + + return ( +
+ + + + + + + +
+ ) +} + +export default App diff --git a/apps/aztec-compiler/src/app/components/Compile.tsx b/apps/aztec-compiler/src/app/components/Compile.tsx new file mode 100644 index 00000000000..508331fb7db --- /dev/null +++ b/apps/aztec-compiler/src/app/components/Compile.tsx @@ -0,0 +1,310 @@ +import React, { useState, useEffect, useRef, useContext } from 'react' +import JSZip from 'jszip' +import axios from 'axios' +import { PluginContext } from '../contexts/pluginContext' +import { CustomTooltip } from '@remix-ui/helper' +import { ImportExampleSelector } from './compile/ImportExampleSelector' +import { TargetProjectSelector } from './compile/TargetProjectSelector' +import { CompileStatusPanel } from './compile/CompileStatusPanel' +import { FileUtil } from '../utils/fileutils' +import { ModalDialog } from '@remix-ui/modal-dialog' + +const BASE_URL = + process.env.NODE_ENV === 'development' + ? process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_DEV + : process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_PROD + +const WS_URL = + process.env.NODE_ENV === 'development' + ? process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_DEV + : process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_PROD + +export const Compile = () => { + const [version] = useState('v0.85.0') + const [projectList, setProjectList] = useState([]) + const [targetProject, setTargetProject] = useState('') + const [compileError, setCompileError] = useState(null) + const [compileLogs, setCompileLogs] = useState([]) + const [loading, setLoading] = useState(false) + const [queuePosition, setQueuePosition] = useState(null) + const [examples, setExamples] = useState([]) + const [exampleToImport, setExampleToImport] = useState('') + const wsRef = useRef(null) + const requestIdRef = useRef('') + const { plugin: client } = useContext(PluginContext) + const [modal, setModal] = useState({ hide: true, title: '', message: '', okLabel: 'Close' }) + + const showModal = (title: string, message: string) => { + setModal({ hide: false, title, message, okLabel: 'Close' }) + } + const hideModal = () => setModal({ ...modal, hide: true }) + + useEffect(() => { + const fetchExamples = async () => { + try { + const res = await axios.get(`${BASE_URL}/examples`) + setExamples(res.data.examples) + } catch { + console.error('Failed to fetch examples') + } + } + fetchExamples() + }, []) + + useEffect(() => { + getList() + return () => wsRef.current?.readyState === WebSocket.OPEN && wsRef.current.close() + }, []) + + const generateUniqueId = () => { + const timestamp = new Date().toISOString().replace(/[-:.]/g, '') + const rand = Math.random().toString(36).substring(2, 8) + return `req_${timestamp}_${rand}` + } + + const getList = async () => { + const projects = await getProjectHaveTomlFile('browser/aztec') + setProjectList(projects) + setTargetProject(projects[0] || '') + } + + const setTarget = (e: { target: { value: string } }) => { + setTargetProject(e.target.value) + } + + const getProjectHaveTomlFile = async (path: string): Promise => { + if (!client) return [] + const projects: string[] = [] + const findTomlFileRecursively = async (currentPath: string): Promise => { + const list = await client.call('fileManager', 'readdir', currentPath); + const hasTomlFile = Object.keys(list).some((item) => item.endsWith('Nargo.toml')) + if (hasTomlFile) { + projects.push(currentPath.replace('browser/', '')) + } + for (const [key, value] of Object.entries(list)) { + if ((value as any).isDirectory) { + const additionalPath = key.split('/').pop() + await findTomlFileRecursively(currentPath + '/' + additionalPath) + } + } + } + await findTomlFileRecursively(path) + return projects + } + + const getAllProjectFiles = async (projectPath: string) => { + const files = await FileUtil.allFilesForBrowser(client, projectPath) + return files.filter((file) => !file.path.startsWith(`${projectPath}/target`)) + } + + const generateZip = async (files: any[], projectPath: string) => { + const zip = new JSZip() + await Promise.all( + files.map(async (file) => { + if (!file.isDirectory) { + const content = await client.call('fileManager', 'readFile', file.path); + const relativePath = file.path.replace('browser/', '') + const zipPath = relativePath.replace(`${projectPath}/`, '') + zip.file(zipPath, content) + } + }) + ) + return zip.generateAsync({ type: 'blob' }) + } + + const handleCompile = async () => { + if (!targetProject) { + showModal('Error', 'No target project selected!') + return + } + + setLoading(true) + setCompileLogs([]) + requestIdRef.current = generateUniqueId() + + const ws = new WebSocket(`${WS_URL}`) + wsRef.current = ws + + await new Promise((resolve, reject) => { + ws.onopen = () => { + ws.send(JSON.stringify({ requestId: requestIdRef.current })) + resolve() + } + ws.onerror = (error) => { + console.error('[Frontend] WebSocket connection error:', error) + reject(new Error('WebSocket connection failed')) + } + }) + + ws.onmessage = async (event) => { + try { + const parsed = JSON.parse(event.data) + if (parsed.logMsg) { + setCompileLogs((prev) => [...prev, parsed.logMsg]) + await client.call('terminal', 'log', { + type: 'info', + value: parsed.logMsg + }) + } + } catch (e) { + console.warn('[Frontend] Invalid WebSocket message:', event.data) + } + } + + ws.onerror = () => { + showModal('Error', 'WebSocket connection failed') + setLoading(false) + } + + try { + const projFiles = await getAllProjectFiles(targetProject) + const zipBlob = await generateZip(projFiles, targetProject) + + const formData = new FormData() + formData.append('file', zipBlob, `${targetProject}.zip`) + formData.append('projectPath', targetProject) + + const response = await axios.post( + `${BASE_URL}/compile?requestId=${requestIdRef.current}`, + formData + ) + + if (!response.data || !response.data.url) { + throw new Error('S3 URL not returned from backend') + } + + const zipResponse = await axios.get(response.data.url, { responseType: 'arraybuffer' }) + const compiledZip = await JSZip.loadAsync(zipResponse.data) + + await Promise.all( + Object.entries(compiledZip.files).map(async ([path, file]) => { + if (!file.dir) { + const content = await file.async('string') + const remixPath = `browser/${targetProject}/${path}` + await client.call('fileManager', 'writeFile', remixPath, content) + } + }) + ) + + await client.call('terminal', 'log', { + type: 'info', + value: 'Compilation completed!' + }) + showModal('Success', `Compilation completed! JSON generated under ${targetProject}/target`) + } catch (error: any) { + showModal('Error', `Compilation failed: ${error.message}`) + await client.call('terminal', 'log', { + type: 'error', + value: `Compilation failed: ${error.message}` + }) + } finally { + setLoading(false) + if (ws.readyState === WebSocket.OPEN) { + ws.close() + } + } + } + + const checkQueueStatus = async () => { + try { + const res = await axios.get(`${BASE_URL}/queue/status`, { + params: { requestId: requestIdRef.current }, + }) + setQueuePosition(res.data.position) + } catch (err) { + console.warn('Failed to check queue status', err) + } + } + + const importExample = async (exampleName: string) => { + if (!client) return + const targetPath = `browser/aztec/${exampleName}` + + try { + const existing = await client.call('fileManager', 'readdir', targetPath) + if (Object.keys(existing).length > 0) { + await client.call('terminal', 'log', { + type: 'warn', + value: `⚠️ Project "${exampleName}" already exists. Import canceled.` + }) + return + } + } catch (err) {} + + try { + const res = await axios.get(`${BASE_URL}/examples/url`, { + params: { name: exampleName }, + }) + + if (!res.data.url) throw new Error('No download URL received') + + const zipRes = await axios.get(res.data.url, { responseType: 'arraybuffer' }) + const zip = await JSZip.loadAsync(zipRes.data) + const rootFolder = Object.keys(zip.files)[0]?.split('/')[0] + + await Promise.all( + Object.entries(zip.files).map(async ([zipPath, file]) => { + if (!file.dir && zipPath.startsWith(`${rootFolder}/`)) { + const relativePath = zipPath.replace(`${rootFolder}/`, '') + const remixPath = `${targetPath}/${relativePath}` + const content = await file.async('string') + await client.call('fileManager', 'writeFile', remixPath, content) + } + }) + ) + + await client.call('terminal', 'log', { + type: 'info', + value: `Example "${exampleName}" imported.` + }) + + setTargetProject(`aztec/${exampleName}`) + await getList() + } catch (err: any) { + console.error(`Failed to import example ${exampleName}`, err) + await client.call('terminal', 'log', { + type: 'error', + value: `Failed to import ${exampleName}: ${err.message}` + }) + } + } + + return ( + <> +
+
+ Compiler Version: + {version} +
+
+ + setTargetProject(e.target.value)} + onReload={getList} + /> + + +
+
+ + + ) +} diff --git a/apps/aztec-compiler/src/app/components/compile/CompileStatusPanel.tsx b/apps/aztec-compiler/src/app/components/compile/CompileStatusPanel.tsx new file mode 100644 index 00000000000..d0dd9392793 --- /dev/null +++ b/apps/aztec-compiler/src/app/components/compile/CompileStatusPanel.tsx @@ -0,0 +1,18 @@ +import React from 'react' +import { CustomTooltip } from '@remix-ui/helper' + +export const CompileStatusPanel = ({ loading, queuePosition, checkQueueStatus }) => { + if (!loading) return null + return ( +
+ + {queuePosition !== null && ( +
+ You're currently #{queuePosition + 1} in the queue. +
+ )} +
+ ) +} diff --git a/apps/aztec-compiler/src/app/components/compile/ImportExampleSelector.tsx b/apps/aztec-compiler/src/app/components/compile/ImportExampleSelector.tsx new file mode 100644 index 00000000000..29b485962be --- /dev/null +++ b/apps/aztec-compiler/src/app/components/compile/ImportExampleSelector.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import { CustomTooltip } from '@remix-ui/helper' + +export const ImportExampleSelector = ({ examples, exampleToImport, setExampleToImport, importExample }) => ( +
+
IMPORT EXAMPLE PROJECT
+ + + + +
+) \ No newline at end of file diff --git a/apps/aztec-compiler/src/app/components/compile/TargetProjectSelector.tsx b/apps/aztec-compiler/src/app/components/compile/TargetProjectSelector.tsx new file mode 100644 index 00000000000..14fd2f1261d --- /dev/null +++ b/apps/aztec-compiler/src/app/components/compile/TargetProjectSelector.tsx @@ -0,0 +1,26 @@ +import React from 'react' +import { CustomTooltip } from '@remix-ui/helper' + +export const TargetProjectSelector = ({ projectList, targetProject, setTarget, onReload }) => ( +
+
+ TARGET PROJECT + +
+ + + +
+) \ No newline at end of file diff --git a/apps/aztec-compiler/src/app/contexts/pluginContext.ts b/apps/aztec-compiler/src/app/contexts/pluginContext.ts new file mode 100644 index 00000000000..d3753e39842 --- /dev/null +++ b/apps/aztec-compiler/src/app/contexts/pluginContext.ts @@ -0,0 +1,8 @@ +import { createContext } from 'react' +import { PluginClient } from '@remixproject/plugin' + +export const PluginContext = createContext<{ + plugin: PluginClient + dispatch: React.Dispatch + state: any +}>(null as any) diff --git a/apps/aztec-compiler/src/app/reducers/state.ts b/apps/aztec-compiler/src/app/reducers/state.ts new file mode 100644 index 00000000000..771990349ea --- /dev/null +++ b/apps/aztec-compiler/src/app/reducers/state.ts @@ -0,0 +1,8 @@ +export const initialState = {} + +export const pluginReducer = (state: any, action: any) => { + switch (action.type) { + default: + return state + } +} \ No newline at end of file diff --git a/apps/aztec-compiler/src/app/services/aztecPluginClient.ts b/apps/aztec-compiler/src/app/services/aztecPluginClient.ts new file mode 100644 index 00000000000..a63de295849 --- /dev/null +++ b/apps/aztec-compiler/src/app/services/aztecPluginClient.ts @@ -0,0 +1,22 @@ +import { PluginClient } from '@remixproject/plugin' +import { createClient } from '@remixproject/plugin-webview' +import EventManager from 'events' + +export class AztecPluginClient extends PluginClient { + public internalEvents: EventManager + + constructor() { + super() + createClient(this) + this.internalEvents = new EventManager() + this.onload() + } + + init(): void { + console.log('[aztec-plugin] Initialized!') + } + + onActivation(): void { + this.internalEvents.emit('aztec_activated') + } +} diff --git a/apps/aztec-compiler/src/app/utils/fileutils.ts b/apps/aztec-compiler/src/app/utils/fileutils.ts new file mode 100644 index 00000000000..20dc0c2c220 --- /dev/null +++ b/apps/aztec-compiler/src/app/utils/fileutils.ts @@ -0,0 +1,56 @@ +export interface FileInfo { + path: string; + isDirectory: boolean; +} + +export class FileUtil { + + static async allFilesForBrowser(client: any, dirName: string): Promise { + try { + let result: FileInfo[] = [] + const files = await client?.fileManager.readdir('browser/' + dirName) + for (const [key, val] of Object.entries(files)) { + const file_ = { + path: key, + isDirectory: (val as any).isDirectory, + }; + if (file_.isDirectory) { + const subDirFiles = (await FileUtil.allFilesForBrowser(client, file_.path)) || [] + + result = [...result, file_, ...subDirFiles] + } else { + result.push(file_) + } + } + return result + } catch (e) { + console.error(e) + return []; + } + } + + static extractFilename(path: string): string { + const lastIndex = path.lastIndexOf('/') + if (lastIndex === -1) { + return path + } + + return path.slice(lastIndex + 1) + } + + static extractFilenameWithoutExtension(path: string): string { + const filename = FileUtil.extractFilename(path) + return filename.slice(0, filename.lastIndexOf('.')) + } + + static async contents(fileManager: any, compileTarget: string, projFiles: FileInfo[]) { + return await Promise.all( + projFiles.map(async (u) => { + if (u.isDirectory) { + return '' + } + return await fileManager.readFile('browser/' + compileTarget + '/' + u.path) + }), + ) + } +} \ No newline at end of file diff --git a/apps/aztec-compiler/src/css/app.css b/apps/aztec-compiler/src/css/app.css new file mode 100644 index 00000000000..28bf8fe7857 --- /dev/null +++ b/apps/aztec-compiler/src/css/app.css @@ -0,0 +1,115 @@ +body { + font-size : .8rem; +} +.noir_section { + padding: 12px 24px 16px; +} +.noir_label { + margin-bottom: 2px; + font-size: 11px; + line-height: 12px; + text-transform: uppercase; +} +.noir_warnings_box { + display: flex; + align-items: center; +} +.noir_warnings_box label { + margin: 0; +} +.noir_config_section:hover { + cursor: pointer; +} +.noir_config_section { + font-size: 1rem; +} +.noir_config { + display: flex; + align-items: center; +} +.noir_config label { + margin: 0; +} +.noir_inner_label { + margin-bottom: 2px; + font-size: 11px; + line-height: 12px; + text-transform: uppercase; +} +.circuit_errors_box { + word-break: break-word; +} +.circuit_feedback.success, +.circuit_feedback.error, +.circuit_feedback.warning { + white-space: pre-line; + word-wrap: break-word; + cursor: pointer; + position: relative; + margin: 0.5em 0 1em 0; + border-radius: 5px; + line-height: 20px; + padding: 8px 15px; +} + +.circuit_feedback.success pre, +.circuit_feedback.error pre, +.circuit_feedback.warning pre { + white-space: pre-line; + overflow-y: hidden; + background-color: transparent; + margin: 0; + font-size: 12px; + border: 0 none; + padding: 0; + border-radius: 0; +} + +.circuit_feedback.success .close, +.circuit_feedback.error .close, +.circuit_feedback.warning .close { + visibility: hidden; + white-space: pre-line; + font-weight: bold; + position: absolute; + color: hsl(0, 0%, 0%); /* black in style-guide.js */ + top: 0; + right: 0; + padding: 0.5em; +} + +.circuit_feedback.success a, +.circuit_feedback.error a, +.circuit_feedback.warning a { + bottom: 0; + right: 0; +} +.custom-dropdown-items { + padding: 0.25rem 0.25rem; + border-radius: .25rem; + background: var(--custom-select); +} +.custom-dropdown-items a { + border-radius: .25rem; + text-transform: none; + text-decoration: none; + font-weight: normal; + font-size: 0.875rem; + padding: 0.25rem 0.25rem; + width: auto; + color: var(--text); +} + +.compiler-version { + display: flex; + align-items: center; + gap: 6px; + font-size: 13px; + color: #6c757d; + padding: 0 1rem 0.5rem 1rem; +} + +.compiler-version-value { + color: #ffffff; + font-weight: 500; +} \ No newline at end of file diff --git a/apps/aztec-compiler/src/index.html b/apps/aztec-compiler/src/index.html new file mode 100644 index 00000000000..a41a84c3875 --- /dev/null +++ b/apps/aztec-compiler/src/index.html @@ -0,0 +1,21 @@ + + + + + Aztec - Compiler + + + + + + + + + +
+ + + diff --git a/apps/aztec-compiler/src/main.tsx b/apps/aztec-compiler/src/main.tsx new file mode 100644 index 00000000000..502a6c93a3d --- /dev/null +++ b/apps/aztec-compiler/src/main.tsx @@ -0,0 +1,9 @@ +import React from 'react' +import { createRoot } from 'react-dom/client' +import App from './app/app' + +const container = document.getElementById('root') + +if (container) { + createRoot(container).render() +} \ No newline at end of file diff --git a/apps/aztec-compiler/src/polyfills.ts b/apps/aztec-compiler/src/polyfills.ts new file mode 100644 index 00000000000..2adf3d05b6f --- /dev/null +++ b/apps/aztec-compiler/src/polyfills.ts @@ -0,0 +1,7 @@ +/** + * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. + * + * See: https://github.com/zloirock/core-js#babel + */ +import 'core-js/stable'; +import 'regenerator-runtime/runtime'; diff --git a/apps/aztec-compiler/src/profile.json b/apps/aztec-compiler/src/profile.json new file mode 100644 index 00000000000..6a1c0ae6661 --- /dev/null +++ b/apps/aztec-compiler/src/profile.json @@ -0,0 +1,17 @@ +{ + "name": "aztec-compiler", + "kind": "provider", + "displayName": "Aztec Compiler", + "events": [], + "version": "2.0.0", + "methods": [], + "canActivate": [], + "url": "", + "description": "Enables support for aztec contract compilation", + "icon": "assets/img/noir-icon12.webp", + "location": "sidePanel", + "documentation": "", + "repo": "https://github.com/ethereum/remix-project/tree/master/apps/aztec-compiler", + "maintainedBy": "Remix", + "authorContact": "" +} diff --git a/apps/aztec-compiler/tsconfig.app.json b/apps/aztec-compiler/tsconfig.app.json new file mode 100644 index 00000000000..2272b8a388c --- /dev/null +++ b/apps/aztec-compiler/tsconfig.app.json @@ -0,0 +1,24 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": ["node"] + }, + "files": [ + "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", + "../../node_modules/@nrwl/react/typings/image.d.ts" + ], + "exclude": [ + "jest.config.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/*.spec.tsx", + "**/*.test.tsx", + "**/*.spec.js", + "**/*.test.js", + "**/*.spec.jsx", + "**/*.test.jsx" + ], + "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] + } + \ No newline at end of file diff --git a/apps/aztec-compiler/tsconfig.json b/apps/aztec-compiler/tsconfig.json new file mode 100644 index 00000000000..5aab5e79111 --- /dev/null +++ b/apps/aztec-compiler/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "jsx": "react-jsx", + "allowJs": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + } + ] +} diff --git a/apps/aztec-compiler/webpack.config.js b/apps/aztec-compiler/webpack.config.js new file mode 100644 index 00000000000..5a08c8e89e6 --- /dev/null +++ b/apps/aztec-compiler/webpack.config.js @@ -0,0 +1,113 @@ +const { composePlugins, withNx } = require('@nrwl/webpack') +const webpack = require('webpack') +const TerserPlugin = require("terser-webpack-plugin") +const CssMinimizerPlugin = require("css-minimizer-webpack-plugin") +const path = require('path') + +// Nx plugins for webpack. +module.exports = composePlugins(withNx(), (config) => { + + // add fallback for node modules + config.resolve.fallback = { + ...config.resolve.fallback, + "crypto": require.resolve("crypto-browserify"), + "stream": require.resolve("stream-browserify"), + "path": require.resolve("path-browserify"), + "http": require.resolve("stream-http"), + "https": require.resolve("https-browserify"), + "constants": require.resolve("constants-browserify"), + "os": false, //require.resolve("os-browserify/browser"), + "timers": false, // require.resolve("timers-browserify"), + "zlib": require.resolve("browserify-zlib"), + "fs": false, + "module": false, + "tls": false, + "net": false, + "readline": false, + "child_process": false, + "buffer": require.resolve("buffer/"), + "vm": require.resolve('vm-browserify'), + } + + + // add externals + config.externals = { + ...config.externals, + solc: 'solc', + } + + // add public path + config.output.publicPath = './' + + // add copy & provide plugin + config.plugins.push( + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + url: ['url', 'URL'], + process: 'process/browser', + }) + ) + + // set the define plugin to load the WALLET_CONNECT_PROJECT_ID + config.plugins.push( + new webpack.DefinePlugin({ + WALLET_CONNECT_PROJECT_ID: JSON.stringify(process.env.WALLET_CONNECT_PROJECT_ID), + }) + ) + + config.plugins.push( + new webpack.DefinePlugin({ + 'fetch': `((...args) => { + if (args[0].origin === 'https://github.com') { + return fetch('https://api.allorigins.win/raw?url=' + args[0]) + } + return fetch(...args) + })`, + }) + ) + + // source-map loader + config.module.rules.push({ + test: /\.js$/, + use: ["source-map-loader"], + enforce: "pre" + }) + + config.ignoreWarnings = [/Failed to parse source map/] // ignore source-map-loader warnings + + + // set minimizer + config.optimization.minimizer = [ + new TerserPlugin({ + parallel: true, + terserOptions: { + ecma: 2015, + compress: false, + mangle: false, + format: { + comments: false, + }, + }, + extractComments: false, + }), + new CssMinimizerPlugin(), + ]; + + config.watchOptions = { + ignored: /node_modules/ + } + + config.experiments.syncWebAssembly = true + + config.plugins.push( + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), + 'process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_DEV': JSON.stringify(process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_DEV), + 'process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_PROD': JSON.stringify(process.env.REACT_APP_AZTEC_PLUGIN_API_BASE_URL_PROD), + 'process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_DEV': JSON.stringify(process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_DEV), + 'process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_PROD': JSON.stringify(process.env.REACT_APP_AZTEC_PLUGIN_WS_URL_PROD), + }) + ) + + return config; +}); diff --git a/apps/remix-ide/project.json b/apps/remix-ide/project.json index 744036b2454..a7e64387054 100644 --- a/apps/remix-ide/project.json +++ b/apps/remix-ide/project.json @@ -3,7 +3,7 @@ "$schema": "../../node_modules/nx/schemas/project-schema.json", "sourceRoot": "apps/remix-ide/src", "projectType": "application", - "implicitDependencies": ["doc-gen", "doc-viewer", "contract-verification", "vyper", "solhint", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp", "noir-compiler"], + "implicitDependencies": ["doc-gen", "doc-viewer", "contract-verification", "vyper", "solhint", "circuit-compiler", "learneth", "quick-dapp", "remix-dapp", "noir-compiler", "aztec-compiler"], "targets": { "build": { "executor": "@nrwl/webpack:webpack", diff --git a/apps/remix-ide/src/app/plugins/matomo.ts b/apps/remix-ide/src/app/plugins/matomo.ts index 40c61e718e7..748e053c5cd 100644 --- a/apps/remix-ide/src/app/plugins/matomo.ts +++ b/apps/remix-ide/src/app/plugins/matomo.ts @@ -11,7 +11,7 @@ const profile = { version: '1.0.0' } -const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'scriptRunnerBridge', 'dgit', 'contract-verification', 'noir-compiler'] +const allowedPlugins = ['LearnEth', 'etherscan', 'vyper', 'circuit-compiler', 'doc-gen', 'doc-viewer', 'solhint', 'walletconnect', 'scriptRunner', 'scriptRunnerBridge', 'dgit', 'contract-verification', 'noir-compiler', 'aztec-compiler'] export class Matomo extends Plugin { diff --git a/apps/remix-ide/src/remixAppManager.ts b/apps/remix-ide/src/remixAppManager.ts index 2e048de25e0..93b3abeecc7 100644 --- a/apps/remix-ide/src/remixAppManager.ts +++ b/apps/remix-ide/src/remixAppManager.ts @@ -97,7 +97,7 @@ let requiredModules = [ // dependentModules shouldn't be manually activated (e.g hardhat is activated by remixd) const dependentModules = ['foundry', 'hardhat', 'truffle', 'slither'] -const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'contract-verification', 'vyper', 'solhint', 'circuit-compiler', 'learneth', 'quick-dapp', 'noir-compiler'] +const loadLocalPlugins = ['doc-gen', 'doc-viewer', 'contract-verification', 'vyper', 'solhint', 'circuit-compiler', 'learneth', 'quick-dapp', 'noir-compiler', 'aztec-compiler'] const partnerPlugins = ['cookbookdev'] @@ -153,7 +153,8 @@ export function isNative(name) { 'contract-verification', 'popupPanel', 'LearnEth', - 'noir-compiler' + 'noir-compiler', + 'aztec-compiler', ] return nativePlugins.includes(name) || requiredModules.includes(name) || isInjectedProvider(name) || isVM(name) || isScriptRunner(name) }