UNPKG

4.78 kBJavaScriptView Raw
1const path = require("path");
2const load = require("../../util/load");
3const webpack = load("webpack");
4const cwd = process.cwd();
5const axios = require("axios");
6const getTimeFromDate = date => date.toTimeString().slice(0, 8);
7
8const {
9 YNW_CONFIG_PATH,
10 PRODUCTION,
11 DEVELOPMENT
12} = require("../../util/const");
13const { getPageOption } = require("../../util/fns");
14const openBrowser = require("../../util/openBrowser");
15
16module.exports = argv => main(argv);
17
18async function main(argv) {
19 const package = require("../../package.json");
20 const optionDecorator = require("./options/optionDecorator");
21
22 console.log(`> ynw-cli: ${package.version}`.cyan);
23
24 const inputs = await parseInput(argv);
25 beforeOption(inputs);
26 const options = optionDecorator(createWebpackOption(inputs));
27 beforeCompiler(inputs, options);
28 run(inputs, options);
29}
30
31async function parseInput(argv) {
32 const { build, env } = argv;
33 const defaultOption = {
34 target: "web",
35 env: "dev",
36 port: 9999
37 };
38 const config = require(YNW_CONFIG_PATH);
39 const pageOption = getPageOption(config, build);
40
41 // weight: common < page < cli
42 const options = Object.assign(defaultOption, config.common, pageOption, argv);
43 const isHot = env === "hot";
44 const isDev = env === "dev";
45 const isPro = env === "pro";
46 const notPro = isDev || isHot;
47 const fileName = path.basename(options.entry);
48 const absolutePath = path.join(cwd, options.entry);
49 const projectPath = path.dirname(absolutePath);
50 const distPath =
51 (options.dist && path.join(cwd, options.dist)) ||
52 path.join(projectPath + "/dist/");
53
54 if (isHot) {
55 options.port = await getValidPort(options.port);
56 }
57
58 return Object.assign({}, options, {
59 isHot,
60 isDev,
61 isPro,
62 notPro,
63 fileName,
64 absolutePath,
65 projectPath,
66 distPath
67 });
68}
69
70function beforeOption(inputs) {
71 require("./before/compatibility")(inputs);
72}
73
74function createWebpackOption(inputs) {
75 const entry = require("./options/entry")(inputs);
76 const alias = require("./options/alias")(inputs);
77 const externals = require("./options/externals")(inputs);
78 const plugins = require("./options/plugins")(inputs);
79 const rules = require("./options/rules")(inputs);
80 const devServer = require("./options/devServer")(inputs);
81 const publicPath = require("./options/publicPath")(inputs);
82
83 const chunkFilename = `${inputs.fileName}.chunk.[name].js`;
84
85 return {
86 entry,
87 target: inputs.target,
88 mode: inputs.isPro ? PRODUCTION : DEVELOPMENT,
89 output: {
90 filename: inputs.hash ? "[name].bundle.[hash:5].js" : "[name].bundle.js",
91 path: inputs.distPath,
92 chunkFilename,
93 publicPath
94 },
95 resolve: { alias, extensions: [".js", ".vue", ".jsx", ".json"] },
96 module: { rules },
97 externals,
98 plugins,
99 devServer
100 };
101}
102
103function beforeCompiler(ctx, options) {
104 require("./before/createDev")(ctx, options);
105 require("./before/log")(ctx, options);
106}
107
108function afterCompiler(ctx) {
109 return function() {
110 const buildTime = getTimeFromDate(new Date());
111 const context = { buildTime, ...ctx };
112 require("./after/append")(context);
113 require("./after/print")(context);
114 };
115}
116
117const exec = after => (err, stats) => {
118 if (err) {
119 console.error(err.stack || err);
120 if (err.details) console.error(err.details);
121 return;
122 }
123 const hasError = stats.hasErrors();
124 const buildInfo = stats.toString({
125 chunks: false,
126 colors: true,
127 assets: false,
128 chunkModules: false,
129 chunks: false,
130 children: false,
131 maxModules: 1
132 });
133 console.log(buildInfo);
134 if (!hasError) {
135 after(buildInfo);
136 }
137};
138
139function run(ctx, options) {
140 const { port } = ctx;
141 const { devServer } = options;
142 const compiler = webpack(options);
143
144 const package = {
145 dev: () =>
146 compiler.watch(
147 { aggregateTimeout: 300, poll: 1000 },
148 exec(afterCompiler(ctx))
149 ),
150 pro: () => compiler.run(exec(afterCompiler(ctx))),
151 hot: () => {
152 const WebpackDevServer = load("webpack-dev-server");
153 const url = `http://127.0.0.1:${port}/dev.html`;
154
155 WebpackDevServer.addDevServerEntrypoints(options, devServer);
156 new WebpackDevServer(compiler, devServer).listen(port, "localhost", () =>
157 console.log(`${url}`.green)
158 );
159 setTimeout(() => {
160 try {
161 openBrowser({ url });
162 } catch (err) {
163 console.log("Chrome Not Found!");
164 }
165 }, 1000);
166 }
167 };
168 package[ctx.env]();
169}
170
171async function getValidPort(port = 9999) {
172 const min = port - 20;
173 for (let i = port; i >= min; i--) {
174 let url = `http://localhost:${i}`;
175 const result = await axios
176 .get(url)
177 .then(() => false)
178 .catch(() => true);
179 if (result) {
180 return Promise.resolve(i);
181 }
182 }
183}