makepack 1.5.23 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "makepack",
3
- "version": "1.5.23",
3
+ "version": "1.6.0",
4
4
  "type": "module",
5
5
  "description": "A CLI tool to create, build, and manage JavaScript, TypeScript, React, and React-TypeScript libraries for npm projects.",
6
6
  "files": [
@@ -25,7 +25,7 @@
25
25
  },
26
26
  "homepage": "https://github.com/devnax/makepack#readme",
27
27
  "scripts": {
28
- "start": "node ./src/index.js start",
28
+ "start": "node ./src/index.js start --port 3000",
29
29
  "create": "node ./src/index.js create",
30
30
  "build": "node ./src/index.js build"
31
31
  },
@@ -5,106 +5,160 @@ import chalk from 'chalk'
5
5
  import ora from 'ora'
6
6
  import { glob } from 'glob'
7
7
  import ts from 'typescript'
8
- import makepackConfig from '../../makepack-config.js'
9
8
 
10
- const build = async () => {
9
+ const eBuild = async (ebconfig) => {
10
+
11
+ await esbuild.build({
12
+ jsx: 'automatic',
13
+ ...ebconfig,
14
+ outExtension: { '.js': ebconfig.format === "esm" ? '.mjs' : ".cjs" },
15
+ loader: {
16
+ '.ts': 'ts',
17
+ '.tsx': 'tsx'
18
+ },
19
+ outdir: path.join(process.cwd(), '.mpack'),
20
+ })
21
+ }
22
+
23
+ const build = async (args) => {
24
+ /* args
25
+ --format=default
26
+ --bundle=true,
27
+ --minify=false,
28
+ --sourcemap=true,
29
+ --platform=node,
30
+ --target=es2020,
31
+ */
32
+
33
+
34
+ let printBool = (f) => typeof args[f] === 'string' ? (args[f] === 'true') : args[f];
35
+
36
+ args = {
37
+ format: args.format || "default",
38
+ bundle: printBool('bundle'),
39
+ minify: printBool('minify'),
40
+ sourcemap: printBool('sourcemap'),
41
+ platform: args.platform || "",
42
+ target: args.target || "es2020",
43
+ declaration: printBool('declaration'),
44
+ }
45
+
46
+ const outdir = path.join(process.cwd(), '.mpack');
47
+ if (fs.existsSync(outdir)) {
48
+ fs.rmSync(outdir, { recursive: true, force: true });
49
+ }
50
+ fs.mkdirSync(outdir)
11
51
 
12
52
  const spinner = ora("Generating a production build for the package...").start();
53
+ const files = await glob("src/**/*.{tsx,ts,js,jsx}") || [];
54
+ const entryPoints = files.map(entry => path.join(process.cwd(), entry));
55
+ let batchSize = args.format === 'default' ? 300 : 500;
13
56
 
14
- try {
15
- const { build } = await makepackConfig()
16
- const configs = build.configs
17
- if (!configs || !configs.length) process.exit("Invalid configuration");
18
- const outdir = path.join(process.cwd(), build.outdir)
19
-
20
- try {
21
- fs.removeSync(outdir);
22
- fs.mkdirSync(outdir);
23
- } catch (err) { }
24
-
25
- const batchSize = 500;
26
- for (let ebconfig of configs) {
27
- const files = await glob(ebconfig.entryPoints) || [];
28
- const entryPoints = files.map(entry => path.join(process.cwd(), entry));
29
- for (let i = 0; i < entryPoints.length; i += batchSize) {
30
- const batch = entryPoints.slice(i, i + batchSize);
31
- await esbuild.build({
32
- ...ebconfig,
33
- entryPoints: batch,
34
- outdir: path.join(outdir, ebconfig.outdir || ''),
35
- });
36
- }
57
+ let ebconfig = {
58
+ bundle: args.bundle,
59
+ minify: args.minify,
60
+ sourcemap: args.sourcemap,
61
+ platform: args.platform,
62
+ target: args.target,
63
+ }
64
+
65
+ for (let i = 0; i < entryPoints.length; i += batchSize) {
66
+ const batch = entryPoints.slice(i, i + batchSize);
67
+ let config = {
68
+ ...ebconfig,
69
+ entryPoints: batch,
70
+ }
71
+ if (args.format === 'default') {
72
+ await eBuild({ ...config, format: "esm" });
73
+ spinner.succeed('ESM build generated successfully!');
74
+ await eBuild({ ...config, format: "cjs" });
75
+ spinner.succeed('CJS build generated successfully!');
76
+ } else {
77
+ await eBuild({ ...config, format: args.format });
78
+ spinner.succeed(`${args.format} build generated successfully!`);
37
79
  }
80
+ }
38
81
 
39
- if (build.types) {
40
- const tsconfigPath = path.resolve(process.cwd(), "tsconfig.json");
41
- let tsconfig = {};
42
- if (fs.existsSync(tsconfigPath)) {
43
- const parsedConfig = ts.getParsedCommandLineOfConfigFile(
44
- tsconfigPath,
45
- {},
46
- ts.sys
47
- );
48
-
49
- if (!parsedConfig) {
50
- console.error("❌ Error parsing tsconfig.json");
51
- process.exit(1);
52
- } else {
53
- tsconfig = parsedConfig.options;
54
- }
55
- }
56
82
 
57
- tsconfig = {
58
- allowJs: true,
59
- target: ts.ScriptTarget.ESNext, // Ensure it's an enum
60
- skipLibCheck: true,
61
- moduleResolution: ts.ModuleResolutionKind.Node10,
62
- ...tsconfig, // Preserve root tsconfig settings
63
- outDir: path.join(outdir, "types"),
64
- declaration: true,
65
- emitDeclarationOnly: true,
66
- noEmit: false,
67
- };
68
-
69
- spinner.text = "Generating TypeScript declarations..."
70
- const files = await glob("src/**/*.{tsx,ts,js,jsx}") || []
71
- const program = ts.createProgram(files, tsconfig);
72
- const emitResult = program.emit();
73
- const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
74
-
75
- if (diagnostics.length > 0) {
76
- diagnostics.forEach(diagnostic => {
77
- const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
78
- if (diagnostic.file) {
79
- const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
80
- spinner.fail(`Error at ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
81
- } else {
82
- spinner.fail(`Error: ${message}`);
83
- }
84
- });
83
+ if (args.declaration) {
84
+ const tsconfigPath = path.resolve(process.cwd(), "tsconfig.json");
85
+ let tsconfig = {};
86
+ if (fs.existsSync(tsconfigPath)) {
87
+ const parsedConfig = ts.getParsedCommandLineOfConfigFile(
88
+ tsconfigPath,
89
+ {},
90
+ ts.sys
91
+ );
92
+
93
+ if (!parsedConfig) {
94
+ console.error("❌ Error parsing tsconfig.json");
95
+ process.exit(1);
85
96
  } else {
86
- spinner.succeed("TypeScript declaration files generated successfully!")
97
+ tsconfig = parsedConfig.options;
87
98
  }
88
99
  }
89
100
 
90
- spinner.text = "Copying package.json and readme.md files..."
91
- let packageJson = JSON.parse(fs.readFileSync(path.join(process.cwd(), '/package.json'), 'utf8'));
92
- const formatPackageJson = build.formatPackageJson || ((p) => p)
93
- packageJson = formatPackageJson(packageJson)
101
+ tsconfig = {
102
+ allowJs: true,
103
+ target: ts.ScriptTarget.ESNext, // Ensure it's an enum
104
+ skipLibCheck: true,
105
+ moduleResolution: ts.ModuleResolutionKind.Node10,
106
+ ...tsconfig, // Preserve root tsconfig settings
107
+ outDir: outdir,
108
+ declaration: true,
109
+ emitDeclarationOnly: true,
110
+ noEmit: false,
111
+ };
94
112
 
95
- fs.writeFileSync(path.join(process.cwd(), build.outdir, '/package.json'), JSON.stringify(packageJson, null, 2));
96
- fs.copyFileSync(path.join(process.cwd(), '/readme.md'), path.join(process.cwd(), build.outdir, `/readme.md`))
97
- spinner.succeed('Production build generated successfully! The package is ready for deployment.')
113
+ spinner.text = "Generating TypeScript declarations..."
114
+ const program = ts.createProgram(files, tsconfig);
115
+ const emitResult = program.emit();
116
+ const diagnostics = ts.getPreEmitDiagnostics(program).concat(emitResult.diagnostics);
98
117
 
99
- console.log(`\nTo publish your package:`);
100
- console.log(`run: ${chalk.green(`makepack publish`)} to publish the package directly from the current project.`);
101
- console.log(chalk.yellow(`OR`));
102
- console.log(`${chalk.yellow(`Navigate to the ${build.outdir} directory:`)} ${chalk.green(`cd ./${build.outdir}`)} and run ${chalk.green(`npm publish`)}`);
118
+ if (diagnostics.length > 0) {
119
+ diagnostics.forEach(diagnostic => {
120
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
121
+ if (diagnostic.file) {
122
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
123
+ spinner.fail(`Error at ${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`);
124
+ } else {
125
+ spinner.fail(`Error: ${message}`);
126
+ }
127
+ });
128
+ } else {
129
+ spinner.succeed("TypeScript declaration files generated successfully!")
130
+ }
131
+ }
132
+ spinner.text = "Copying package.json and readme.md files..."
133
+
134
+ // update package.json to include the .mpack directory
135
+ const pkgPath = path.join(process.cwd(), 'package.json');
136
+ if (fs.existsSync(pkgPath)) {
137
+ const pkgjson = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
138
+ if (args.format === 'default') {
139
+ pkgjson.main = "./index.cjs";
140
+ pkgjson.module = "./index.mjs";
141
+ pkgjson.types = './index.d.ts'
142
+ } else {
143
+ let t = args.format === 'mjs' ? 'module' : 'main';
144
+ pkgjson[t] = `./index.${args.format}`;
145
+ }
103
146
 
104
- } catch (error) {
105
- spinner.fail("An error occurred while generating the production build.")
106
- console.error(error);
147
+ if (args.declaration) {
148
+ pkgjson.types = `index.${args.format}.d.ts`;
149
+ }
150
+
151
+ fs.writeFileSync(path.join(outdir, 'package.json'), JSON.stringify(pkgjson, null, 2));
152
+ } else {
153
+ spinner.fail("package.json not found!");
154
+ return;
107
155
  }
156
+
157
+ fs.copyFileSync(path.join(process.cwd(), '/readme.md'), path.join(outdir, `/readme.md`))
158
+ spinner.succeed("package.json and readme.md files copied successfully!")
159
+ console.log(chalk.green(`\nBuild completed successfully!`));
160
+ console.log(`\nTo publish your package to npm:`);
161
+ console.log(`${chalk.green(`npm run publish`)} or navigate to the ${chalk.green(`.mpack`)} directory and run ${chalk.green(`npm publish`)}`);
108
162
  }
109
163
 
110
164
  export default build
@@ -1,9 +1,10 @@
1
- import makepackConfig from "../../../makepack-config.js"
2
1
 
3
2
  export default async () => {
4
- const config = await makepackConfig()
5
3
  return {
6
- content: `node_modules\n${config.build.outdir}`,
4
+ content: `
5
+ node_modules
6
+ .mpack
7
+ `,
7
8
  filename: ".gitignore"
8
9
  }
9
10
  }
@@ -3,11 +3,14 @@ export default async (info) => {
3
3
  let dependencies = {}
4
4
  let devDependencies = {
5
5
  "makepack": "latest",
6
- "react": "^19.0.0",
7
- "react-dom": "^19.0.0",
8
6
  "express": "latest"
9
7
  }
10
8
 
9
+ if (info.template.includes("react")) {
10
+ dependencies["react"] = "^19.0.0"
11
+ dependencies["react-dom"] = "^19.0.0"
12
+ }
13
+
11
14
  if (info.template.includes("typescript")) {
12
15
  devDependencies["typescript"] = "^4.4.2"
13
16
  devDependencies["@types/react"] = "^19.0.2"
@@ -15,34 +18,32 @@ export default async (info) => {
15
18
  devDependencies["@types/express"] = "latest"
16
19
  }
17
20
 
18
- let main = info.sourceEntry.split('.')
19
- main.pop()
20
-
21
21
  const json = {
22
- name: info.projectDirName,
22
+ name: info.pdir,
23
23
  version: "1.0.0",
24
- main: `./cjs/index.js`,
25
- module: `./index.js`,
26
- types: `./types/index.d.ts`,
24
+ main: `./index.cjs`,
25
+ module: `./index.mjs`,
26
+ types: `./index.d.ts`,
27
27
  description: "",
28
28
  keywords: [],
29
- "exports": {
30
- ".": {
31
- "types": "./types/index.d.ts",
32
- "require": "./cjs/index.js",
33
- "import": "./index.js",
34
- },
35
- "./types/*": "./types/*.d.ts",
36
- "./cjs/*": "./cjs/*.js",
37
- "./*": {
38
- "import": "./*.js",
39
- "require": "./cjs/*.js"
40
- }
41
- },
29
+ sideEffects: false,
30
+ // "exports": {
31
+ // ".": {
32
+ // "types": "./types/index.d.ts",
33
+ // "require": "./cjs/index.js",
34
+ // "import": "./index.js",
35
+ // },
36
+ // "./types/*": "./types/*.d.ts",
37
+ // "./cjs/*": "./cjs/*.js",
38
+ // "./*": {
39
+ // "import": "./*.js",
40
+ // "require": "./cjs/*.js"
41
+ // }
42
+ // },
42
43
  scripts: {
43
44
  "start": "makepack start",
44
45
  "build": "makepack build",
45
- "build:publish": "makepack publish"
46
+ "publish": "makepack publish"
46
47
  },
47
48
  dependencies,
48
49
  devDependencies
@@ -1,4 +1,4 @@
1
- export default async (args) => {
1
+ export default async () => {
2
2
  const content = `
3
3
  function add(a, b) {
4
4
  return a + b;
@@ -8,6 +8,6 @@ export default add
8
8
  `
9
9
  return {
10
10
  content,
11
- filename: `${args.sourceDir}/${args.sourceEntry}`
11
+ filename: `src/index.js`
12
12
  }
13
13
  }
@@ -1,7 +1,8 @@
1
- export default async (args) => {
1
+ export default async () => {
2
2
  const content = `import React, { useState } from 'react';
3
+ import { createRoot } from 'react-dom/client';
3
4
 
4
- const Count = () => {
5
+ const App = () => {
5
6
  const [count, setCount] = useState(0);
6
7
  const increment = () => setCount(prevCount => prevCount + 1);
7
8
  const decrement = () => setCount(prevCount => prevCount - 1);
@@ -42,10 +43,14 @@ const styles = {
42
43
  },
43
44
  };
44
45
 
45
- export default Count;
46
+ const rootEle = document.getElementById('root')
47
+ if (rootEle) {
48
+ const root = createRoot(rootEle);
49
+ root.render(<App />);
50
+ }
46
51
  `
47
52
  return {
48
53
  content,
49
- filename: `${args.sourceDir}/${args.sourceEntry}`
54
+ filename: `src/index.jsx`
50
55
  }
51
56
  }
@@ -1,4 +1,4 @@
1
- export default async (args) => {
1
+ export default async () => {
2
2
  const content = `
3
3
  function add(a: number, b: number): number {
4
4
  return a + b;
@@ -6,6 +6,6 @@ function add(a: number, b: number): number {
6
6
  export default add`
7
7
  return {
8
8
  content,
9
- filename: `${args.sourceDir}/${args.sourceEntry}`
9
+ filename: `src/index.ts`
10
10
  }
11
11
  }
@@ -1,7 +1,8 @@
1
- export default async (args) => {
1
+ export default async () => {
2
2
  const content = `import React, { useState } from 'react';
3
+ import { createRoot } from 'react-dom/client';
3
4
 
4
- const Count: React.FC = () => {
5
+ const App: React.FC = () => {
5
6
  const [count, setCount] = useState<number>(0);
6
7
  const increment = (): void => setCount(prevCount => prevCount + 1);
7
8
  const decrement = (): void => setCount(prevCount => prevCount - 1);
@@ -42,10 +43,14 @@ const styles: { [key: string]: React.CSSProperties } = {
42
43
  },
43
44
  };
44
45
 
45
- export default Count;
46
+ const rootEle = document.getElementById('root')
47
+ if (rootEle) {
48
+ const root = createRoot(rootEle);
49
+ root.render(<App />);
50
+ }
46
51
  `
47
52
  return {
48
53
  content,
49
- filename: `${args.sourceDir}/${args.sourceEntry}`
54
+ filename: `src/index.tsx`
50
55
  }
51
56
  }
@@ -23,7 +23,7 @@ export default async () => {
23
23
  "include": ["src"],
24
24
  "exclude": [
25
25
  "node_modules",
26
- "build"
26
+ ".mpack",
27
27
  ]
28
28
  }
29
29
 
@@ -4,29 +4,55 @@ import path from 'path'
4
4
  import inquirer from 'inquirer'
5
5
  import figlet from 'figlet'
6
6
  import fs from "fs-extra"
7
+ import chalk from 'chalk';
7
8
  const cwd = process.cwd()
8
9
  const cwdFolder = cwd.split(path.sep).pop()
9
10
 
10
- const create = async () => {
11
- const information = {
12
- projectDirName: cwdFolder,
13
- cwd: path.join(cwd, cwdFolder),
14
- template: "typescript",
15
- sourceDir: "src",
16
- sourceEntry: "index.ts",
11
+ const valiateProjectName = (name) => {
12
+ if (!name) {
13
+ console.error("Project name cannot be empty.");
14
+ return false;
15
+ }
16
+ if (!/^[a-z0-9-]+$/.test(name)) {
17
+ console.error("Project name can only contain lowercase letters, numbers, and hyphens.");
18
+ return false;
19
+ }
20
+ if (name.length < 3) {
21
+ console.error("Project name must be at least 3 characters long.");
22
+ return false;
23
+ }
24
+ if (name.length > 50) {
25
+ console.error("Project name must be less than 50 characters long.");
26
+ return false;
17
27
  }
28
+ return true;
29
+ }
30
+
31
+ const create = async () => {
18
32
 
19
- let { projectDirName } = await inquirer.prompt([
33
+ let info = await inquirer.prompt([
20
34
  {
21
35
  type: 'input',
22
- name: 'projectDirName',
36
+ name: 'pdir',
23
37
  message: 'Enter the project name',
24
- default: information.projectDir
38
+ default: cwdFolder
39
+ },
40
+ {
41
+ type: 'list',
42
+ name: 'template',
43
+ message: 'Select a template',
44
+ choices: ['typescript', 'javascript', 'react with typescript', 'react with javascript'],
45
+ default: "typescript"
25
46
  }
26
47
  ])
27
48
 
28
- if (projectDirName !== cwdFolder) {
29
- if (fs.existsSync(path.join(cwd, projectDirName))) {
49
+ // check if the pdir is exists
50
+ let pdir = info.pdir.trim().replace(/\s+/g, '-').toLowerCase();
51
+ const isValidProjectName = valiateProjectName(pdir)
52
+ if (!isValidProjectName) return
53
+
54
+ if (pdir !== cwdFolder) {
55
+ if (fs.existsSync(path.join(cwd, pdir))) {
30
56
  const { proceed } = await inquirer.prompt([
31
57
  {
32
58
  type: "confirm",
@@ -42,58 +68,30 @@ const create = async () => {
42
68
  }
43
69
  }
44
70
 
45
- information.projectDirName = projectDirName
46
- information.cwd = path.join(cwd, information.projectDirName)
47
- let isCurrentDir = projectDirName !== cwdFolder
48
-
49
- // template
50
- const { template } = await inquirer.prompt([
51
- {
52
- type: 'list',
53
- name: 'template',
54
- message: 'Select a template',
55
- choices: ['typescript', 'javascript', 'react with typescript', 'react with javascript'],
56
- default: information.template
57
- }
58
- ])
59
-
60
- information.template = template
61
-
71
+ const rootdir = path.join(cwd, pdir)
72
+ let isCurrentDir = pdir !== cwdFolder
62
73
  logger.info("", "Creating project...", false)
63
- const projectDir = path.join(cwd, information.projectDirName)
64
-
65
- if (!fs.existsSync(projectDir)) {
66
- fs.mkdirSync(projectDir)
67
- }
68
74
 
69
- if (!fs.existsSync(path.join(projectDir, information.sourceDir))) {
70
- fs.mkdirSync(path.join(projectDir, information.sourceDir))
75
+ if (!fs.existsSync(rootdir)) {
76
+ fs.mkdirSync(rootdir)
71
77
  }
72
78
 
73
- switch (information.template) {
74
- case "react with typescript":
75
- information.sourceEntry = "index.tsx"
76
- break;
77
- case "react with javascript":
78
- information.sourceEntry = "index.jsx"
79
- break;
80
- case "javascript":
81
- information.sourceEntry = "index.js"
82
- break;
79
+ if (!fs.existsSync(path.join(rootdir, 'src'))) {
80
+ fs.mkdirSync(path.join(rootdir, 'src'))
83
81
  }
84
82
 
85
- await makeFiles(information)
83
+ await makeFiles(info)
86
84
 
87
85
  logger.info("", "Installing Dependencies", false)
88
86
  execSync("npm install", {
89
- cwd: information.cwd,
87
+ cwd: rootdir,
90
88
  })
91
89
 
92
- logger.info("Project setup complete!", "", false)
90
+ logger.success("Project setup complete!", "")
93
91
  if (isCurrentDir) {
94
- console.log(`Run the development server: \n${logger.info("", "npm start", false)}\nEnjoy your new project! 😊`);
92
+ console.log(`Run the development server: ${chalk.blue("npm start")}\nEnjoy your new project! 😊`);
95
93
  } else {
96
- console.log(`To start working with your project:\nNavigate to your project directory:\n${logger.info("", "cd " + information.projectDirName, false)} and Run the development server:\n${logger.info("", "npm start", false)}\nEnjoy your new project! 😊`);
94
+ console.log(`Navigate to your project directory:\n${chalk.blue("cd " + info.pdir, false)} and Run the development server: ${chalk.blue("npm start")}\nEnjoy your new project! 😊`);
97
95
  }
98
96
 
99
97
  figlet("Makepack CLI", function (err, data) {
@@ -1,7 +1,6 @@
1
1
  // import makepack from "./files/makepack.js";
2
2
  import packageJson from "./files/package-json.js";
3
3
  import gitignore from "./files/gitignore.js";
4
- import App from "./files/App.js";
5
4
  import tsconfig from "./files/tsconfig.js";
6
5
  import projectJs from "./files/project-js.js";
7
6
  import projectJsx from "./files/project-jsx.js";
@@ -17,7 +16,6 @@ export default async (info) => {
17
16
  const files = [
18
17
  await packageJson(info),
19
18
  await gitignore(info),
20
- await App(info),
21
19
  await readmeMd(info)
22
20
  ];
23
21
 
@@ -41,9 +39,11 @@ export default async (info) => {
41
39
  files.push(await tsconfig(info))
42
40
  }
43
41
 
42
+ const rootdir = path.join(process.cwd(), info.pdir)
43
+
44
44
  for (let file of files) {
45
45
  // check if the file exists
46
- if (fs.existsSync(path.join(info.cwd, file.filename))) {
46
+ if (fs.existsSync(path.join(rootdir, file.filename))) {
47
47
  const { overwrite } = await inquirer.prompt([
48
48
  {
49
49
  type: "confirm",
@@ -55,10 +55,10 @@ export default async (info) => {
55
55
  if (!overwrite) {
56
56
  continue
57
57
  } else {
58
- fs.removeSync(path.join(info.cwd, file.filename))
58
+ fs.removeSync(path.join(rootdir, file.filename))
59
59
  }
60
60
  }
61
61
 
62
- fs.writeFileSync(path.join(info.cwd, file.filename), file.content)
62
+ fs.writeFileSync(path.join(rootdir, file.filename), file.content)
63
63
  }
64
64
  }
@@ -1,14 +1,13 @@
1
1
  import path from 'path'
2
2
  import { execSync, logger } from '../../helpers.js'
3
- import makepackConfig from '../../makepack-config.js'
4
3
  import fs from 'fs-extra'
5
4
 
6
5
  const publish = async () => {
7
- const { build } = await makepackConfig()
8
- const buildDir = path.join(process.cwd(), build.outdir)
6
+ const buildDir = path.join(process.cwd(), '.mpack')
7
+ const packageJsonPath = path.join(buildDir, 'package.json')
9
8
  const exists = fs.existsSync(buildDir)
10
- if (!exists) {
11
- logger.error(`Build directory ${buildDir} does not exist. Please build the project first`)
9
+ if (!exists || !fs.existsSync(packageJsonPath)) {
10
+ logger.error(`Project is not built yet. Please build the project first.`)
12
11
  process.exit(1)
13
12
  }
14
13
 
@@ -1,25 +1,42 @@
1
1
  import express from 'express';
2
2
  import { logger } from '../../helpers.js'
3
3
  import chalk from 'chalk';
4
- import makepackConfig from '../../makepack-config.js';
4
+ import path from 'path'
5
+ import fs from 'fs'
5
6
  import viteSetup from './vite.js';
6
- import userExpress from './user-express.js';
7
-
7
+ const port = process.env.PORT || 3000;
8
8
  const app = express();
9
9
  const server = async () => {
10
- const config = await makepackConfig()
11
- userExpress(app)
10
+
11
+ // get type from package.json
12
+ const pkg = path.join(process.cwd(), 'package.json');
13
+ let type = 'module';
14
+ if (fs.existsSync(pkg)) {
15
+ const pkgjson = JSON.parse(fs.readFileSync(pkg, 'utf-8'));
16
+ type = pkgjson.type || 'module';
17
+ }
18
+
19
+ const mpack = path.join(process.cwd(), '.mpack');
20
+ const uxp = path.join(mpack, 'uxp.js')
21
+ if (fs.existsSync(uxp)) {
22
+ // load user-express.js based on type
23
+ if (type === 'module') {
24
+ const { default: userExpress } = await import(uxp);
25
+ userExpress(app);
26
+ } else {
27
+ const userExpress = require(uxp).default;
28
+ userExpress(app);
29
+ }
30
+ }
31
+
32
+
12
33
  await viteSetup(app)
13
34
  app.use((_req, res) => {
14
35
  res.status(500).send('Internal Server Error');
15
36
  });
16
37
 
17
- app.listen(config.start.port, () => {
18
- logger.success(`Server is running on ${chalk.blue(chalk.underline(`http://localhost:${config.start.port}`))}`);
19
- });
20
-
21
- process.on('SIGINT', async () => {
22
- process.exit(0);
38
+ app.listen(port, () => {
39
+ logger.success(`Server is running on ${chalk.blue(chalk.underline(`http://localhost:${port}`))}`);
23
40
  });
24
41
  }
25
42
 
@@ -1,11 +1,10 @@
1
- import fs from 'fs-extra'
2
1
  import path from 'path'
3
- import { logger } from '../../helpers.js'
4
- import makepackConfig from '../../makepack-config.js';
2
+ import fs from 'fs'
3
+ import { spawn } from 'child_process'
5
4
  import esbuild from 'esbuild';
6
- import chokidar from 'chokidar';
7
5
  import { fileURLToPath } from 'url';
8
- import { spawn } from 'child_process';
6
+ import chokidar from 'chokidar';
7
+
9
8
  let __filename, __dirname;
10
9
 
11
10
  if (typeof import.meta.url !== 'undefined') {
@@ -16,62 +15,104 @@ if (typeof import.meta.url !== 'undefined') {
16
15
  __dirname = __dirname;
17
16
  }
18
17
 
19
- let server = null;
20
- function startServer() {
21
- if (server) {
22
- server.kill('SIGINT');
23
- server = null;
24
- }
25
- server = spawn('node', [path.resolve(__dirname, 'express.js')], {});
26
- server.stdout.on('data', (data) => {
27
- console.log(data.toString().trim());
18
+
19
+ const startServer = () => {
20
+ const mpack = path.join(process.cwd(), '.mpack')
21
+ const server = spawn('node', [path.resolve(mpack, 'index.js')], {
22
+ stdio: 'inherit',
28
23
  });
29
- server.stderr.on('data', (data) => {
30
- console.error(data.toString().trim());
24
+
25
+ server.on('error', (err) => {
26
+ console.error(`Error starting server: ${err.message}`);
31
27
  });
28
+ return server;
32
29
  }
33
30
 
34
- const start = async () => {
35
- const config = await makepackConfig()
36
- const exists = fs.existsSync(path.join(process.cwd(), config.start.entry))
37
- if (!exists) {
38
- logger.error(`Entry file ${entry} does not exist. please check your config file`)
39
- process.exit(1)
31
+ const start = async (args) => {
32
+ let { port } = args
33
+
34
+ if (!port) {
35
+ port = 4000;
36
+ }
37
+ // create a folder call .mpack
38
+ const mpack = path.join(process.cwd(), '.mpack')
39
+ if (fs.existsSync(mpack)) {
40
+ fs.rmSync(mpack, { recursive: true, force: true });
41
+ }
42
+ fs.mkdirSync(mpack)
43
+
44
+
45
+ // build ./express.js to .mpack/index.js with esbuild
46
+ let format = 'esm'
47
+ // get format from package.json
48
+ const pkg = path.join(process.cwd(), 'package.json')
49
+ if (fs.existsSync(pkg)) {
50
+ const pkgjson = JSON.parse(fs.readFileSync(pkg, 'utf-8'))
51
+ if (pkgjson.type === 'commonjs') {
52
+ format = 'cjs'
53
+ }
40
54
  }
41
55
 
42
- const expressjs = path.join(process.cwd(), 'express.js')
43
- const expressts = path.join(process.cwd(), 'express.ts')
56
+ const uxpjs = path.join(process.cwd(), 'express.js')
57
+ const uxpts = path.join(process.cwd(), 'express.ts')
44
58
 
45
- if (fs.existsSync(expressjs) || fs.existsSync(expressts)) {
46
- let filename = fs.existsSync(expressjs) ? "express.js" : "express.ts";
47
- let outfile = path.resolve(__dirname, 'user-express.js')
59
+ if (fs.existsSync(uxpjs) || fs.existsSync(uxpts)) {
60
+ let filename = fs.existsSync(uxpjs) ? "express.js" : "express.ts";
61
+ let outfile = path.join(mpack, 'uxp.js');
48
62
 
49
63
  const ctx = await esbuild.context({
50
64
  entryPoints: [filename],
51
- outfile: path.resolve(__dirname, 'user-express.js'),
65
+ outfile,
52
66
  bundle: true,
53
67
  format: 'esm',
54
68
  platform: 'node',
55
69
  packages: 'external',
56
70
  })
57
-
58
71
  ctx.watch()
72
+ }
73
+
74
+ await esbuild.build({
75
+ entryPoints: [path.resolve(__dirname, 'express.js')],
76
+ outfile: path.join(mpack, 'index.js'),
77
+ bundle: true,
78
+ format,
79
+ platform: 'node',
80
+ packages: 'external',
81
+ define: {
82
+ 'process.env.PORT': JSON.stringify(port),
83
+ },
84
+ })
85
+
86
+ let server = startServer();
87
+
88
+ const uxp = path.join(mpack, 'uxp.js')
59
89
 
60
- const watcher = chokidar.watch(outfile, {
90
+ if (fs.existsSync(uxp)) {
91
+ const watcher = chokidar.watch(uxp, {
61
92
  persistent: true,
62
93
  ignoreInitial: true,
63
94
  });
64
95
 
65
96
  watcher.on('change', async () => {
66
- startServer(config)
67
- });
68
-
69
- process.on('SIGINT', async () => {
70
- watcher.close();
71
- process.exit(0);
97
+ // restart the server and remove log Server exited with code
98
+ server.kill();
99
+ server = startServer();
72
100
  });
73
101
  }
74
- startServer(config)
102
+
103
+ process.on('SIGINT', () => {
104
+ console.log('Received SIGINT, killing server...');
105
+ server.kill('SIGINT');
106
+ process.exit(0);
107
+ });
108
+
109
+ process.on('SIGTERM', () => {
110
+ console.log('Received SIGTERM, killing server...');
111
+ server.kill('SIGTERM');
112
+ process.exit(0);
113
+ });
114
+
75
115
  }
76
116
 
117
+
77
118
  export default start
@@ -1,10 +1,10 @@
1
1
  // import react from '@vitejs/plugin-react'
2
2
  import { createServer as createViteServer } from 'vite';
3
3
  import { logger } from '../../helpers.js'
4
- import makepackConfig from '../../makepack-config.js';
4
+ import path from 'path';
5
+ import fs from 'fs';
5
6
 
6
7
  const viteSetup = async (app) => {
7
- const config = await makepackConfig()
8
8
  const viteConfig = {
9
9
  root: process.cwd(),
10
10
  base: "/",
@@ -25,6 +25,11 @@ const viteSetup = async (app) => {
25
25
  const vite = await createViteServer(viteConfig);
26
26
  app.use(vite.middlewares);
27
27
 
28
+ // exists tsconfig.json in the root directory
29
+ const isTs = fs.existsSync(path.resolve(process.cwd(), 'tsconfig.json'))
30
+
31
+ let entry = isTs ? '/src/index.ts' : '/src/index.js';
32
+
28
33
  app.get('*', async (req, res, next) => {
29
34
  const url = req.originalUrl;
30
35
 
@@ -38,7 +43,7 @@ const viteSetup = async (app) => {
38
43
  </head>
39
44
  <body>
40
45
  <div id="root"></div>
41
- <script type="module" src="${config.start.entry}"></script>
46
+ <script type="module" src="${entry}"></script>
42
47
  </body>
43
48
  </html>
44
49
  `);
package/src/index.js CHANGED
@@ -12,17 +12,25 @@ program.name("Makepack").description("Usages");
12
12
 
13
13
  program
14
14
  .command("create")
15
- .description("create a new project")
15
+ .description("Create a new project")
16
16
  .action(create);
17
17
 
18
18
  program
19
19
  .command("start")
20
+ .option("-p, --port <port>", "Port to run the server", 3000)
20
21
  .description("Start the server")
21
22
  .action(start);
22
23
 
23
24
  program
24
25
  .command("build")
25
26
  .description("Build the project")
27
+ .option("-f, --format <format>", "Output format (cjs, esm, umd, default)", "default")
28
+ .option("-b, --bundle <bundle>", "Bundle the project", false)
29
+ .option("-m, --minify <minify>", "Minify the output", true)
30
+ .option("-s, --sourcemap <sourcemap>", "Generate sourcemaps", true)
31
+ .option("-t, --target <target>", "Target ECMAScript version", "es2020")
32
+ .option("-p, --platform <platform>", "Platform to target (node, browser)", "")
33
+ .option("-d, --declaration <declaration>", "Generate TypeScript declaration files", true)
26
34
  .action(build);
27
35
 
28
36
  program
@@ -1,52 +0,0 @@
1
- export default async (info) => {
2
- let ext = info.template.includes('typescript') ? ".tsx" : ".jsx"
3
- let _import = ''
4
- let _code = ''
5
-
6
- switch (info.template) {
7
- case "typescript":
8
- case "javascript":
9
- _import = `import add from './${info.sourceDir}'`
10
- _code = `<code>{add(5,5)}</code>`
11
- break
12
- case "react with typescript":
13
- case "react with javascript":
14
- _import = `import Count from './${info.sourceDir}'`
15
- _code = `<Count />`
16
- break;
17
- }
18
-
19
- const content = `import React from 'react';
20
- import { createRoot } from 'react-dom/client';
21
- ${_import}
22
-
23
- const App = () => {
24
- return (
25
- <div style={{fontFamily: 'monospace,math, sans-serif', textAlign: 'center', marginTop: '50px' }}>
26
- <h1>Welcome to makepack CLI!</h1>
27
- <p>Edit <code>index.tsx</code> and save to reload.</p>
28
- <a
29
- href="https://reactjs.org"
30
- target="_blank"
31
- rel="noopener noreferrer"
32
- style={{ color: '#61dafb', textDecoration: 'none' }}
33
- >
34
- Learn React
35
- </a>
36
- <div style={{marginTop: "50px"}}>
37
- ${_code}
38
- </div>
39
- </div>
40
- );
41
- }
42
- const rootEle = document.getElementById('root')
43
- if (rootEle) {
44
- const root = createRoot(rootEle);
45
- root.render(<App />);
46
- }
47
- `
48
- return {
49
- content,
50
- filename: `App${ext}`
51
- }
52
- }
@@ -1,55 +0,0 @@
1
- import { loadConfig } from "../../../helpers.js"
2
-
3
- export default async (info) => {
4
- const config = await loadConfig()
5
- let dependencies = {}
6
- let devDependencies = {
7
- "makepack": "latest",
8
- "react": "^19.0.0",
9
- "react-dom": "^19.0.0",
10
- "express": "latest"
11
- }
12
-
13
- if (args.template.includes("typescript")) {
14
- devDependencies["typescript"] = "^4.4.2"
15
- devDependencies["@types/react"] = "^19.0.2"
16
- devDependencies["@types/react-dom"] = "^19.0.2"
17
- devDependencies["@types/express"] = "latest"
18
- }
19
-
20
- let main = args.entry.split('.')
21
- main.pop()
22
-
23
- const json = {
24
- name: args.dirname,
25
- version: "1.0.0",
26
- main: `./${config.build.outdir}/cjs/index.js`,
27
- module: `./${config.build.outdir}/index.js`,
28
- types: `./${config.build.outdir}/index.d.ts`,
29
- description: "",
30
- keywords: [],
31
- exports: {
32
- ".": {
33
- "types": `./${config.build.outdir}/index.d.ts`,
34
- "import": `./${config.build.outdir}/index.js`,
35
- "require": `./${config.build.outdir}/cjs/index.js`
36
- },
37
- "./*": {
38
- "import": `./${config.build.outdir}/*.js`,
39
- "require": `./${config.build.outdir}/cjs/*.js`
40
- }
41
- },
42
- scripts: {
43
- "start": "makepack serve",
44
- "build": "makepack build",
45
- "prepare": "npm run build",
46
- },
47
- dependencies,
48
- devDependencies
49
- }
50
-
51
- return {
52
- content: JSON.stringify(json, null, 3),
53
- filename: "package.json"
54
- }
55
- }
@@ -1,7 +0,0 @@
1
- // express.ts
2
- var expressApp = (app) => {
3
- };
4
- var express_default = expressApp;
5
- export {
6
- express_default as default
7
- };
@@ -1,59 +0,0 @@
1
- import { cosmiconfig } from "cosmiconfig";
2
-
3
- const makepackConfig = async () => {
4
- const explorer = cosmiconfig("makepack");
5
- const configResult = await explorer.search();
6
-
7
- const defaultConfig = {
8
- build: {
9
- outdir: "build",
10
- types: true,
11
- formatPackageJson: (p) => p,
12
- configs: [
13
- {
14
- entryPoints: "src/**/*.{tsx,ts,js,jsx}",
15
- outdir: "",
16
- format: "esm",
17
- sourcemap: true,
18
- minify: true,
19
- jsx: 'automatic',
20
- loader: {
21
- '.ts': 'ts',
22
- '.tsx': 'tsx'
23
- },
24
- },
25
- {
26
- entryPoints: "src/**/*.{tsx,ts,js,jsx}",
27
- outdir: "cjs",
28
- format: "cjs",
29
- sourcemap: true,
30
- minify: true,
31
- jsx: 'automatic',
32
- loader: {
33
- '.ts': 'ts',
34
- '.tsx': 'tsx'
35
- },
36
- }
37
- ]
38
- },
39
- start: {
40
- port: 5000,
41
- entry: "App.tsx",
42
- }
43
- }
44
-
45
- if (configResult && configResult.config) {
46
- let fn = configResult.config;
47
- if (typeof fn === 'function') {
48
- const userConfig = fn(defaultConfig)
49
- if (!userConfig) {
50
- console.log("Config function must return a config object")
51
- process.exit(1)
52
- }
53
- return userConfig
54
- }
55
- }
56
- return defaultConfig
57
- }
58
-
59
- export default makepackConfig