Skip to content

Commit

Permalink
feat: migrate editor-ui to Vite.js and various DX improvements (N8N-2…
Browse files Browse the repository at this point in the history
…277) (n8n-io#4061)

* feat: Added vite.js dependencies.

* chore: Removed tests folder to follow same structure as design-system

* chore: Removed unused testing config.

* chore: Created vite.js index.html

* refactor: Updated scss structure and imports.

* refactor: Updated workflow building.

* fix: Cleared up all workflow dependency cycles. Added proper package.json imports config.

* feat: Got a working build using Vite. Need to fix issues next.

* fix: Progress! Getting process.env error.

* fix: Changed process.env to import.meta.env.

* fix: Fixed circular imports that used require(). Fixed monaco editor.

* chore: Removed commented code.

* chore: Cleaned up package.json

* feat: Made necessary changes to replace base path in css files.

* feat: Serve CSS files for `editor-ui` Vite migration (n8n-io#4069)

:zap: Serve CSS files for Vite migration

* chore: Fixed package-lock.json.

* fix: Fixed build after centralized tsconfig update.

* fix: Removed lodash-es replacement.

* fix: Commented out vitest test command.

* style: Fixed linting issues.

* fix: Added lodash-es hotfix back.

* chore: Updated package-lock.json

* refactor: Renamed all n8n scss variables to no longer be defined as private.

* feat(editor): add application-wide el-button replacement.

* fix(editor): Fix import in page alert after merge.

* chore(editor): update package-lock.json.

* fix: Case sensitive lodash-es replacement for vue-agile.

* fix: add alias for lodash-es camelcase import.

* fix: add patch-package support for fixing quill

* feat: add patch-package on postinstall

* fix: update quill patch path.

* refactor: rename quill patch

* fix: update quill version.

* fix: update quill patch

* fix: fix linting rules after installing eslint in design-system

* fix: update date picker button to have primary color

* test: update callout component snapshots

* fix(editor): fix linting issues in editor after enabling eslint

* fix(cli): add /assets/* to auth ignore endpoints in server

* chore: update package-lock.json

* chore: update package-lock.json

* fix(editor): fix linting issues

* feat: add vite-legacy support

* fix: update workflow package interface imports to type imports.

* chore: update package-lock.json

* fix(editor) fix importing translations other than english

* fix(editor): remove test command until vitest is added

* fix: increase memory allocation for vite build

* fix: add patch-package patches to n8n-custom docker build

* fix: add performance and load time improvements

* fix: add proper typing to setNodeType

* chore: update package-lock.json

* style: use generic type for reduce in setNodeType

Co-authored-by: Iván Ovejero <[email protected]>
  • Loading branch information
alexgrozav and ivov authored Sep 23, 2022
1 parent 36b2a56 commit 4963319
Show file tree
Hide file tree
Showing 248 changed files with 6,208 additions and 10,833 deletions.
1 change: 1 addition & 0 deletions docker/images/n8n-custom/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ RUN \

COPY turbo.json package.json package-lock.json tsconfig.json ./
COPY packages ./packages
COPY patches ./patches

RUN chown -R node:node .
RUN npm config set legacy-peer-deps true
Expand Down
15,674 changes: 5,457 additions & 10,217 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"lint": "turbo run lint",
"lintfix": "turbo run lintfix",
"optimize-svg": "find ./packages -name '*.svg' ! -name 'pipedrive.svg' -print0 | xargs -0 -P16 -L20 npx svgo",
"postinstall": "patch-package",
"start": "run-script-os",
"start:default": "cd packages/cli/bin && ./n8n",
"start:tunnel": "./packages/cli/bin/n8n start --tunnel",
Expand All @@ -21,6 +22,7 @@
"worker": "./packages/cli/bin/n8n worker"
},
"devDependencies": {
"patch-package": "^6.4.7",
"rimraf": "^3.0.2",
"run-script-os": "^1.0.7",
"turbo": "1.2.15"
Expand Down
29 changes: 28 additions & 1 deletion packages/cli/src/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ import {
WebhookServer,
WorkflowExecuteAdditionalData,
} from '.';
import glob from 'fast-glob';
import { ResponseError } from './ResponseHelper';

require('body-parser-xml')(bodyParser);
Expand Down Expand Up @@ -389,6 +390,7 @@ class App {
const excludeEndpoints = config.getEnv('security.excludeEndpoints');

const ignoredEndpoints = [
'assets',
'healthz',
'metrics',
this.endpointWebhook,
Expand Down Expand Up @@ -1753,11 +1755,28 @@ class App {
const editorUiPath = require.resolve('n8n-editor-ui');
const filePath = pathJoin(pathDirname(editorUiPath), 'dist', 'index.html');
const n8nPath = config.getEnv('path');
const basePathRegEx = /\/%BASE_PATH%\//g;

let readIndexFile = readFileSync(filePath, 'utf8');
readIndexFile = readIndexFile.replace(/\/%BASE_PATH%\//g, n8nPath);
readIndexFile = readIndexFile.replace(basePathRegEx, n8nPath);
readIndexFile = readIndexFile.replace(/\/favicon.ico/g, `${n8nPath}favicon.ico`);

const cssPath = pathJoin(pathDirname(editorUiPath), 'dist', '**/*.css');
const cssFiles: Record<string, string> = {};
glob.sync(cssPath).forEach((filePath) => {
let readFile = readFileSync(filePath, 'utf8');
readFile = readFile.replace(basePathRegEx, n8nPath);
cssFiles[filePath.replace(pathJoin(pathDirname(editorUiPath), 'dist'), '')] = readFile;
});

const jsPath = pathJoin(pathDirname(editorUiPath), 'dist', '**/*.js');
const jsFiles: Record<string, string> = {};
glob.sync(jsPath).forEach((filePath) => {
let readFile = readFileSync(filePath, 'utf8');
readFile = readFile.replace(basePathRegEx, n8nPath);
jsFiles[filePath.replace(pathJoin(pathDirname(editorUiPath), 'dist'), '')] = readFile;
});

const hooksUrls = config.getEnv('externalFrontendHooksUrls');

let scriptsString = '';
Expand Down Expand Up @@ -1793,6 +1812,14 @@ class App {
res.send(readIndexFile);
});

this.app.get('/assets/*.css', async (req: express.Request, res: express.Response) => {
res.type('text/css').send(cssFiles[req.url]);
});

this.app.get('/assets/*.js', async (req: express.Request, res: express.Response) => {
res.type('text/javascript').send(jsFiles[req.url]);
});

// Serve the website
this.app.use(
'/',
Expand Down
36 changes: 0 additions & 36 deletions packages/design-system/gulpfile.js

This file was deleted.

15 changes: 5 additions & 10 deletions packages/design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,15 @@
"url": "git+https://github.com/n8n-io/n8n.git"
},
"scripts": {
"build": "npm run build:theme",
"build:vue": "vite build",
"build": "vite build",
"build:vue:typecheck": "vue-tsc --emitDeclarationOnly",
"dev": "npm run watch:theme",
"test": "vitest run",
"test:ci": "vitest run --coverage",
"test:dev": "vitest",
"build:storybook": "build-storybook",
"storybook": "start-storybook -p 6006",
"lint": "tslint -p tsconfig.json -c tslint.json && eslint .",
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json && eslint . --fix",
"build:theme": "gulp build:theme",
"watch:theme": "gulp watch:theme"
"lintfix": "tslint --fix -p tsconfig.json -c tslint.json && eslint . --fix"
},
"peerDependencies": {
"@fortawesome/fontawesome-svg-core": "1.x",
Expand Down Expand Up @@ -54,10 +50,9 @@
"babel-loader": "^8.2.2",
"c8": "7.11.0",
"core-js": "^3.6.5",
"gulp": "^4.0.0",
"gulp-autoprefixer": "^4.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-dart-sass": "^1.0.2",
"eslint": "^8.0.0",
"eslint-plugin-prettier": "^3.4.0",
"eslint-plugin-vue": "^7.16.0",
"jsdom": "19.0.0",
"markdown-it": "^12.3.2",
"markdown-it-emoji": "^2.0.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ import Vue from 'vue';
export default Vue.extend({
name: 'n8n-action-toggle',
components: {
ElDropdown,
ElDropdownMenu,
ElDropdownItem,
ElDropdown, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdownMenu, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
ElDropdownItem, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
N8nIcon,
},
props: {
Expand Down
2 changes: 1 addition & 1 deletion packages/design-system/src/components/N8nAvatar/Avatar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default Vue.extend({
},
},
components: {
Avatar,
Avatar, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
computed: {
initials() {
Expand Down
22 changes: 11 additions & 11 deletions packages/design-system/src/components/N8nButton/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -96,25 +96,25 @@ export default Vue.extend({
return this.disabled ? 'true' : 'false';
},
classes(): string {
return `button ${this.$style['button']} ${this.$style[this.type]}` +
return `button ${this.$style.button} ${this.$style[this.type]}` +
`${this.size ? ` ${this.$style[this.size]}` : ''}` +
`${this.outline ? ` ${this.$style['outline']}` : ''}` +
`${this.loading ? ` ${this.$style['loading']}` : ''}` +
`${this.outline ? ` ${this.$style.outline}` : ''}` +
`${this.loading ? ` ${this.$style.loading}` : ''}` +
`${this.float ? ` ${this.$style[`float-${this.float}`]}` : ''}` +
`${this.text ? ` ${this.$style['text']}` : ''}` +
`${this.disabled ? ` ${this.$style['disabled']}` : ''}` +
`${this.block ? ` ${this.$style['block']}` : ''}` +
`${this.active ? ` ${this.$style['active']}` : ''}` +
`${this.icon || this.loading ? ` ${this.$style['icon']}` : ''}` +
`${this.square ? ` ${this.$style['square']}` : ''}`;
`${this.text ? ` ${this.$style.text}` : ''}` +
`${this.disabled ? ` ${this.$style.disabled}` : ''}` +
`${this.block ? ` ${this.$style.block}` : ''}` +
`${this.active ? ` ${this.$style.active}` : ''}` +
`${this.icon || this.loading ? ` ${this.$style.icon}` : ''}` +
`${this.square ? ` ${this.$style.square}` : ''}`;
},
},
});
</script>

<style lang="scss" module>
@import '../../../theme/src/mixins/utils';
@import '../../../theme/src/common/var';
@import '../../css/mixins/utils';
@import '../../css/common/var';
.button {
display: inline-block;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import ElButton from "./ElButton.vue";

export default ElButton;
8 changes: 3 additions & 5 deletions packages/design-system/src/components/N8nCallout/Callout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
<script lang="ts">
import Vue from 'vue';
import N8nIcon from '../N8nIcon';
import N8nText from '../N8nText';
const CALLOUT_DEFAULT_ICONS: { [key: string]: string } = {
info: 'info-circle',
Expand All @@ -32,7 +31,6 @@ export default Vue.extend({
name: 'n8n-callout',
components: {
N8nIcon,
N8nText,
},
props: {
theme: {
Expand All @@ -43,14 +41,14 @@ export default Vue.extend({
},
icon: {
type: String,
default: 'info-circle'
default: 'info-circle',
},
},
computed: {
classes(): string[] {
return [
'n8n-callout',
this.$style['callout'],
this.$style.callout,
this.$style[this.theme],
];
},
Expand All @@ -61,7 +59,7 @@ export default Vue.extend({
return this.icon;
},
}
},
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`components > N8nCallout > should render additional slots correctly 1`]
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"code-branch\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp; <n8n-link-stub size=\\"small\\">Do something!</n8n-link-stub>
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp; <n8n-link-stub size=\\"small\\">Do something!</n8n-link-stub>
</div>
<n8n-link-stub theme=\\"secondary\\" size=\\"small\\" bold=\\"true\\" underline=\\"true\\" to=\\"https://n8n.io\\">Learn more</n8n-link-stub>
</div>"
Expand All @@ -18,7 +18,7 @@ exports[`components > N8nCallout > should render custom theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"code-branch\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Expand All @@ -29,7 +29,7 @@ exports[`components > N8nCallout > should render danger theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"times-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a danger callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a danger callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Expand All @@ -40,7 +40,7 @@ exports[`components > N8nCallout > should render info theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"info-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is an info callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is an info callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Expand All @@ -51,7 +51,7 @@ exports[`components > N8nCallout > should render secondary theme correctly 1`] =
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"info-circle\\" size=\\"medium\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a secondary callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a secondary callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Expand All @@ -62,7 +62,7 @@ exports[`components > N8nCallout > should render success theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"check-circle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a success callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a success callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Expand All @@ -73,7 +73,7 @@ exports[`components > N8nCallout > should render warning theme correctly 1`] = `
<div class=\\"_icon_p74de_40\\">
<n8n-icon-stub icon=\\"exclamation-triangle\\" size=\\"large\\"></n8n-icon-stub>
</div>
<n8n-text-stub size=\\"small\\" tag=\\"span\\">This is a warning callout.</n8n-text-stub>&nbsp;
<n8n-text-stub size=\\"small\\">This is a warning callout.</n8n-text-stub>&nbsp;
</div>
</div>"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import N8nInputLabel from '../N8nInputLabel';
export default Vue.extend({
name: 'n8n-checkbox',
components: {
ElCheckbox,
ElCheckbox, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
N8nInputLabel,
},
props: {
Expand Down Expand Up @@ -59,7 +59,7 @@ export default Vue.extend({
onChange(event: Event) {
this.$emit("input", event);
},
}
},
});
</script>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export default mixins(Locale).extend({
},
methods: {
getValidationError(): ReturnType<IValidator['validate']> {
const rules = (this.validationRules || []) as (Rule | RuleGroup)[];
const rules = (this.validationRules || []) as Array<Rule | RuleGroup>;
const validators = {
...VALIDATORS,
...(this.validators || {}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,19 @@ export default Vue.extend({
});
if (this.eventBus) {
this.eventBus.$on('submit', this.onSubmit);
this.eventBus.$on('submit', this.onSubmit); // eslint-disable-line @typescript-eslint/unbound-method
}
},
computed: {
filteredInputs(): IFormInput[] {
return (this.inputs as IFormInput[]).filter(
(input) => typeof input.shouldDisplay === 'function'
? input.shouldDisplay(this.values)
: true
: true,
);
},
isReadyToSubmit(): boolean {
for (let key in this.validity) {
for (const key in this.validity) {
if (!this.validity[key]) {
return false;
}
Expand All @@ -92,17 +92,17 @@ export default Vue.extend({
onInput(name: string, value: any) {
this.values = {
...this.values,
[name]: value,
[name]: value, // eslint-disable-line @typescript-eslint/no-unsafe-assignment
};
this.$emit('input', {name, value});
this.$emit('input', {name, value}); // eslint-disable-line @typescript-eslint/no-unsafe-assignment
},
onValidate(name: string, valid: boolean) {
Vue.set(this.validity, name, valid);
},
onSubmit() {
this.showValidationWarnings = true;
if (this.isReadyToSubmit) {
const toSubmit = (this.filteredInputs as IFormInput[]).reduce<{ [key: string]: unknown }>((accu, input) => {
const toSubmit = (this.filteredInputs ).reduce<{ [key: string]: unknown }>((accu, input) => {
if (this.values[input.name]) {
accu[input.name] = this.values[input.name];
}
Expand Down
Loading

0 comments on commit 4963319

Please sign in to comment.