From 6dd3812bcec9778252c9c00ceb84bb63afd2415c Mon Sep 17 00:00:00 2001 From: luoxue Date: Mon, 9 Dec 2019 14:50:45 +0800 Subject: [PATCH] =?UTF-8?q?feat(eslint):=20=E5=A2=9E=E5=8A=A0=20eslint?= =?UTF-8?q?=EF=BC=8C=E5=B9=B6=E4=BF=9D=E5=AD=98=E6=98=AF=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 28 ++++++ .vscode/settings.json | 72 ++++++++++++++ CHANGELOG.md | 1 + bin/webpack-box.js | 18 ++-- box.config.js | 14 +-- build/base.js | 15 +-- build/build.js | 70 +++++++------- build/dll.js | 81 ++++++++-------- build/lint.js | 16 ++++ build/ssr:server.js | 46 ++++----- cli/CommandAPI.js | 18 ++-- cli/PluginAPI.js | 73 +++++++++++++++ commitlint.config.js | 2 +- config/eslintLoader.js | 50 ++++++++++ dist/index/1.bundle.js.map | 2 +- dist/index/index.bundle.js | 5 +- dist/index/index.bundle.js.gz | Bin 1082 -> 1081 bytes dist/index/index.bundle.js.map | 2 +- dist/index2/1.bundle.js.map | 2 +- dist/index2/index.bundle.js.map | 2 +- dist/index2/index2.bundle.js.map | 2 +- options-chain-loader.js | 24 ++--- package.json | 11 +++ packages/eslint/lint.js | 129 ++++++++++++++++++++++++++ packages/stylelint/index.js | 42 +++++++++ packages/stylelint/lint.js | 104 +++++++++++++++++++++ packages/stylelint/stylelintError.js | 38 ++++++++ packages/stylelint/utils.js | 18 ++++ packages/tslint/generator/index.js | 1 + packages/tslint/index.js | 18 ++++ packages/tslint/lint.js | 134 +++++++++++++++++++++++++++ packages/tslint/prompts.js | 1 + src/main.js | 16 ++-- src/ssr.jsx | 15 ++- src/treeShaking.js | 6 +- webapck-plugin-copy.js | 9 +- 36 files changed, 910 insertions(+), 175 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .vscode/settings.json create mode 100644 build/lint.js create mode 100644 cli/PluginAPI.js create mode 100644 config/eslintLoader.js create mode 100644 packages/eslint/lint.js create mode 100644 packages/stylelint/index.js create mode 100644 packages/stylelint/lint.js create mode 100644 packages/stylelint/stylelintError.js create mode 100644 packages/stylelint/utils.js create mode 100644 packages/tslint/generator/index.js create mode 100644 packages/tslint/index.js create mode 100644 packages/tslint/lint.js create mode 100644 packages/tslint/prompts.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..8b0d5a0f --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,28 @@ +console.log('--------eslint-------') +module.exports = { + root: true, + env: { + browser: true, + node: true + }, + extends: [ + 'plugin:vue/essential', + 'eslint:recommended', + 'standard' + ], + rules: { + 'no-new': 0, + 'max-len': 0, + 'space-before-function-paren': 0, + 'eslint-disable-next-line': 0, + 'no-useless-escape': 0 + }, + globals: { + wx: true, + window: true, + document: true + }, + parserOptions: { + parser: '@typescript-eslint/parser' + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..9f11a0df --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,72 @@ +{ + /* + * @description 编译器配置 + * @param tabSize 默认tab为两个空格 + * @param formatOnSave 保存时自动修复 + */ + "editor.tabSize": 2, + "editor.formatOnSave": true, + /* + * @description eslint 配置 + * @param alwaysShowStatus 配置 + * @param autoFixOnSave 保存时自动修复 + * @param validate 在vue中添加错误提示 + */ + "eslint.alwaysShowStatus": true, + "eslint.autoFixOnSave": true, + "eslint.validate": [ + "javascript", + "javascriptreact", + { + "language": "vue", + "autoFix": true + } + ], + /* + * @description tslint 配置 + * @param autoFixOnSave 保存时自动修复 + * @param alwaysShowRuleFailuresAsWarnings 所有特征都是用 Warnings + */ + "tslint.autoFixOnSave": true, + "tslint.alwaysShowRuleFailuresAsWarnings": true, + /* + * @description stylelint 配置 + * @param autoFixOnSave 保存时自动修复 + */ + "stylelint.autoFixOnSave": true, + /* + * @description vetur 配置 + */ + "vetur.format.defaultFormatter.html": "prettier", + "vetur.format.defaultFormatterOptions": { + "prettier": { + "semi": false, + "singleQuote": true + } + }, + /* + * @description 配置编辑器设置以覆盖某种语言 + */ + "[typescript]": { + // "editor.defaultFormatter": "esbenp.prettier-vscode" + "editor.defaultFormatter": "eg2.tslint" + }, + "[html]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[vue]": { + "editor.defaultFormatter": "eg2.tslint" + }, + "[javascript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ec5b8e9..0cb73f80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### 🌟 新功能 * **编译:** 提升编译速度,增加了 cache-loader dllPlugin threadLoader ([4d44ad7](https://github.com/luoxue-victor/learn_webpack/commit/4d44ad7)) +* **抽离 commander 层:** 修改脚手架二次调用的bug,增加了commander 层 ([b1aa749](https://github.com/luoxue-victor/learn_webpack/commit/b1aa749)) * **多页面:** webpack配置多页面打包 ([86a0418](https://github.com/luoxue-victor/learn_webpack/commit/86a0418)) * **课题2:** 完成基本构建,js、css打包进html,实现dev跟build环境 ([71a6a19](https://github.com/luoxue-victor/learn_webpack/commit/71a6a19)) * **新增loader配置:** 增加ts、css、less、sass、postcss、babel配置 ([53616f8](https://github.com/luoxue-victor/learn_webpack/commit/53616f8)) diff --git a/bin/webpack-box.js b/bin/webpack-box.js index 31af9fc4..a0b20e7e 100755 --- a/bin/webpack-box.js +++ b/bin/webpack-box.js @@ -1,16 +1,18 @@ #!/usr/bin/env node -process.env.NODE_ENV = "none"; -const commandsName = ["build", "dev", 'dll', 'build:ssr', 'ssr:server']; +process.env.NODE_ENV = 'none' +const commandsName = ['build', 'dev', 'dll', 'build:ssr', 'ssr:server', 'lint'] const { injectCommand, commandComplete, commandName -} = require("../cli/CommandAPI"); -commandName.push(...commandsName); +} = require('../cli/CommandAPI') + +const PluginAPI = require('../cli/PluginAPI') +commandName.push(...commandsName) commandsName.forEach(name => { - const { command } = require(`../build/${name}`); - command(injectCommand); -}); + const { command } = require(`../build/${name}`) + command(injectCommand, PluginAPI) +}) -commandComplete(); +commandComplete() diff --git a/box.config.js b/box.config.js index 64dca293..6d54eaf4 100644 --- a/box.config.js +++ b/box.config.js @@ -2,11 +2,11 @@ module.exports = function (config) { /** * @param {object} dll 开启差分包 * @param {object} pages 多页面配置 通过 box run/build index 来使用 - * @param {function} chainWebpack + * @param {function} chainWebpack * @param {string} entry 入口 - * @param {string} output 出口 - * @param {string} publicPath - * @param {string} port + * @param {string} output 出口 + * @param {string} publicPath + * @param {string} port */ return { entry: 'src/main.js', @@ -20,15 +20,15 @@ module.exports = function (config) { index: { entry: 'src/main.js', template: 'public/index.html', - filename: 'index.html', + filename: 'index.html' }, index2: { entry: 'src/main.js', template: 'public/index2.html', - filename: 'index2.html', + filename: 'index2.html' } }, chainWebpack(config) { } } -} \ No newline at end of file +} diff --git a/build/base.js b/build/base.js index 560bede3..4e309dc8 100644 --- a/build/base.js +++ b/build/base.js @@ -1,8 +1,9 @@ const { findSync } = require('../lib') -const Config = require('webpack-chain'); -const config = new Config(); +const Config = require('webpack-chain') +const config = new Config() const files = findSync('../config') -const path = require('path'); +const path = require('path') +const PluginAPI = require('../cli/PluginAPI') const resolve = (p) => { return path.join(process.cwd(), p) } @@ -12,10 +13,10 @@ module.exports = (options) => { files.map(_ => { const name = path.basename(_, '.js') - return map.set(name, require(_)({config, resolve, options})) + return map.set(name, require(_)({ config, resolve, options, api: PluginAPI })) }) - map.forEach(v => v()); - + map.forEach(v => v()) + return config -} \ No newline at end of file +} diff --git a/build/build.js b/build/build.js index 2f76c2fb..26271903 100644 --- a/build/build.js +++ b/build/build.js @@ -1,47 +1,47 @@ -module.exports.command = function (injectCommand) { - injectCommand(function({ program,cleanArgs, boxConfig }) { +module.exports.command = function(injectCommand) { + injectCommand(function({ program, cleanArgs, boxConfig }) { program - .command("build [app-page]") - .description(`构建生产环境`) - .option("-r, --report", "打包分析报告") - .option("-d, --dll", "合并差分包") + .command('build [app-page]') + .description('构建生产环境') + .option('-r, --report', '打包分析报告') + .option('-d, --dll', '合并差分包') .action(async (name, cmd) => { - const options = cleanArgs(cmd); - const args = Object.assign(options, { name }, boxConfig); - process.env.NODE_ENV = "production"; + const options = cleanArgs(cmd) + const args = Object.assign(options, { name }, boxConfig) + process.env.NODE_ENV = 'production' if (!name && boxConfig.pages) { - args.clear = true; + args.clear = true Object.keys(boxConfig.pages).forEach(page => { - args.name = page; - action(args); - }); + args.name = page + action(args) + }) } else { - action(args); + action(args) } - }); - }); + }) + }) } function action(options) { - const rimraf = require("rimraf"); - const ora = require("ora"); - const chalk = require("chalk"); - const path = require("path"); + const rimraf = require('rimraf') + const ora = require('ora') + const chalk = require('chalk') + const path = require('path') // 删除 dist 目录 - options.clear && rimraf.sync(path.join(process.cwd(), "dist")); + options.clear && rimraf.sync(path.join(process.cwd(), 'dist')) - const config = require("./base")(options); - const webpack = require("webpack"); - const spinner = ora("开始构建项目..."); - spinner.start(); + const config = require('./base')(options) + const webpack = require('webpack') + const spinner = ora('开始构建项目...') + spinner.start() - if (typeof options.chainWebpack === "function") { - options.chainWebpack(config); + if (typeof options.chainWebpack === 'function') { + options.chainWebpack(config) } webpack(config.toConfig(), function(err, stats) { - spinner.stop(); - if (err) throw err; + spinner.stop() + if (err) throw err process.stdout.write( stats.toString({ colors: true, @@ -49,13 +49,13 @@ function action(options) { children: false, chunks: false, chunkModules: false - }) + "\n\n" - ); + }) + '\n\n' + ) if (stats.hasErrors()) { - console.log(chalk.red("构建失败\n")); - process.exit(1); + console.log(chalk.red('构建失败\n')) + process.exit(1) } - console.log(chalk.cyan("build完成\n")); - }); + console.log(chalk.cyan('build完成\n')) + }) } diff --git a/build/dll.js b/build/dll.js index a83e0b0c..ed5b30a9 100644 --- a/build/dll.js +++ b/build/dll.js @@ -1,62 +1,61 @@ module.exports.command = function(injectCommand) { injectCommand(function({ program, cleanArgs, boxConfig }) { program - .command("dll [app-page]") - .description(`编译差分包`) + .command('dll [app-page]') + .description('编译差分包') .action(async (name, cmd) => { - const options = cleanArgs(cmd); - const args = Object.assign(options, { name }, boxConfig); - action(args); - }); - }); -}; + const options = cleanArgs(cmd) + const args = Object.assign(options, { name }, boxConfig) + action(args) + }) + }) +} function action(options) { - const path = require("path"); - const dllPath = path.join(process.cwd(), "dll"); - const Config = require("webpack-chain"); - const config = new Config(); - const webpack = require("webpack"); - const rimraf = require("rimraf"); - const ora = require("ora"); - const chalk = require("chalk"); - const BundleAnalyzerPlugin = require("../config/BundleAnalyzerPlugin")( + const path = require('path') + const dllPath = path.join(process.cwd(), 'dll') + const Config = require('webpack-chain') + const config = new Config() + const webpack = require('webpack') + const rimraf = require('rimraf') + const ora = require('ora') + const chalk = require('chalk') + const BundleAnalyzerPlugin = require('../config/BundleAnalyzerPlugin')( config - ); + ) - if (options.report) BundleAnalyzerPlugin(); - if (options.dll && !Array.isArray(options.dll.venders)) - throw console.log("请添加 dll.entry"); + if (options.report) BundleAnalyzerPlugin() + if (options.dll && !Array.isArray(options.dll.venders)) { throw console.log('请添加 dll.entry') } options.dll.venders.forEach(_ => config - .entry("dll") + .entry('dll') .add(_) .end() - ); + ) config - .set("mode", "production") + .set('mode', 'production') .output.path(dllPath) - .filename("[name].js") - .library("[name]") + .filename('[name].js') + .library('[name]') .end() - .plugin("DllPlugin") + .plugin('DllPlugin') .use(webpack.DllPlugin, [ { - name: "[name]", - path: path.join(process.cwd(), "dll", "manifest.json") + name: '[name]', + path: path.join(process.cwd(), 'dll', 'manifest.json') } ]) - .end(); + .end() - rimraf.sync(path.join(process.cwd(), "dll")); - const spinner = ora("开始构建项目..."); - spinner.start(); + rimraf.sync(path.join(process.cwd(), 'dll')) + const spinner = ora('开始构建项目...') + spinner.start() webpack(config.toConfig(), function(err, stats) { - spinner.stop(); - if (err) throw err; + spinner.stop() + if (err) throw err process.stdout.write( stats.toString({ colors: true, @@ -64,13 +63,13 @@ function action(options) { children: false, chunks: false, chunkModules: false - }) + "\n\n" - ); + }) + '\n\n' + ) if (stats.hasErrors()) { - console.log(chalk.red("构建失败\n")); - process.exit(1); + console.log(chalk.red('构建失败\n')) + process.exit(1) } - console.log(chalk.cyan("build完成\n")); - }); + console.log(chalk.cyan('build完成\n')) + }) } diff --git a/build/lint.js b/build/lint.js new file mode 100644 index 00000000..4ee904ec --- /dev/null +++ b/build/lint.js @@ -0,0 +1,16 @@ +module.exports.command = function(injectCommand, api) { + injectCommand(function({ program, cleanArgs, boxConfig }) { + program + .command('lint [type]') + .description('修复lint') + .action(async (name, cmd) => { + const options = cleanArgs(cmd) + const args = Object.assign(options, { name }, boxConfig) + action(args, api) + }) + }) +} + +function action (args, api) { + require(`../packages/${args.name}/lint`)({ args, api }) +} diff --git a/build/ssr:server.js b/build/ssr:server.js index ff9abbb9..29519d2b 100644 --- a/build/ssr:server.js +++ b/build/ssr:server.js @@ -1,39 +1,39 @@ module.exports.command = function(injectCommand) { injectCommand(function({ program, cleanArgs, boxConfig }) { program - .command("ssr:server [app-page]") - .description(`服务端渲染`) + .command('ssr:server [app-page]') + .description('服务端渲染') .action(async (name, cmd) => { - const options = cleanArgs(cmd); - const args = Object.assign(options, { name }, boxConfig); - action(args); - }); - }); -}; + const options = cleanArgs(cmd) + const args = Object.assign(options, { name }, boxConfig) + action(args) + }) + }) +} function action(options) { - const express = require("express"); - const { renderToString } = require("react-dom/server"); - const chalk = require("chalk"); + const express = require('express') + const { renderToString } = require('react-dom/server') + const chalk = require('chalk') - const SSR = require("../static/ssr"); - const port = process.env.PORT || 8080; + const SSR = require('../static/ssr') + const port = process.env.PORT || 8080 - server(port); + server(port) function server(port) { - const app = express(); - app.use(express.static("static")); - app.get("/", (req, res) => + const app = express() + app.use(express.static('static')) + app.get('/', (req, res) => res.status(200).send(renderMarkup(renderToString(SSR))) - ); + ) - const empty = " "; + const empty = ' ' const common = `App running at: - - Local: http://127.0.0.1:${port}\n`; - console.log(chalk.cyan("\n" + empty + common)); + - Local: http://127.0.0.1:${port}\n` + console.log(chalk.cyan('\n' + empty + common)) - app.listen(port, () => process.send && process.send("online")); + app.listen(port, () => process.send && process.send('online')) } function renderMarkup(html) { @@ -47,6 +47,6 @@ function action(options) {
${html}
- `; + ` } } diff --git a/cli/CommandAPI.js b/cli/CommandAPI.js index 62b3efc3..716c12fb 100644 --- a/cli/CommandAPI.js +++ b/cli/CommandAPI.js @@ -2,25 +2,25 @@ const fs = require('fs') const path = require('path') const program = require('commander') -const packageConfig = require('../package.json'); +const packageConfig = require('../package.json') const { cleanArgs } = require('../lib') const boxPath = path.join(process.cwd(), 'box.config.js') const chalk = require('chalk') const commandName = exports.commandName = [] -const commandStore = exports.commandStore = []; +const commandStore = exports.commandStore = [] let boxConfig = {} if (fs.existsSync(boxPath)) boxConfig = require(path.join(process.cwd(), 'box.config.js'))() -let status = 'pending'; +let status = 'pending' program .usage(' [options]') .version(packageConfig.version) module.exports.injectCommand = function (cmd) { - if (status === 'done') return console.log('注册命令行时机已经是 done,请提前注册~') - if(typeof cmd !== 'function') return console.log(cmd, '必须是一个函数') - cmd({program, boxConfig, commandName, commandStore, cleanArgs}) + if (status === 'done') return console.error('注册命令行时机已经是 done,请提前注册~') + if (typeof cmd !== 'function') return console.error(cmd, '必须是一个函数') + cmd({ program, boxConfig, commandName, commandStore, cleanArgs }) } module.exports.commandComplete = function() { @@ -34,15 +34,15 @@ function parse() { program.commands.forEach(c => c.on('--help', () => console.log())) } - function commandValidate() { +function commandValidate() { if (process.argv[2] && !commandName.includes(process.argv[2])) { console.log() console.log(chalk.red(` 没有找到 ${process.argv[2]} 命令`)) console.log() program.help() } - + if (!process.argv[2]) { program.help() } -} \ No newline at end of file +} diff --git a/cli/PluginAPI.js b/cli/PluginAPI.js new file mode 100644 index 00000000..9c98e900 --- /dev/null +++ b/cli/PluginAPI.js @@ -0,0 +1,73 @@ +const hash = require('hash-sum') +const path = require('path') + +exports.genCacheConfig = function (id, partialIdentifier, configFiles = []) { + const fs = require('fs') + const cacheDirectory = this.resolve(`node_modules/.cache/${id}`) + + // replace \r\n to \n generate consistent hash + // const fmtFunc = conf => { + // if (typeof conf === 'function') { + // return conf.toString().replace(/\r\n?/g, '\n') + // } + // return conf + // } + + const variables = { + partialIdentifier, + 'cli-service': require('../package.json').version, + 'cache-loader': require('cache-loader/package.json').version, + env: process.env.NODE_ENV, + test: !!process.env.VUE_CLI_TEST, + config: [ + // fmtFunc(this.service.projectOptions.chainWebpack), + // fmtFunc(this.service.projectOptions.configureWebpack) + ] + } + + if (!Array.isArray(configFiles)) { + configFiles = [configFiles] + } + configFiles = configFiles.concat([ + 'package-lock.json', + 'yarn.lock', + 'pnpm-lock.yaml' + ]) + + const readConfig = file => { + const absolutePath = this.resolve(file) + if (!fs.existsSync(absolutePath)) { + return + } + + if (absolutePath.endsWith('.js')) { + // should evaluate config scripts to reflect environment variable changes + try { + return JSON.stringify(require(absolutePath)) + } catch (e) { + return fs.readFileSync(absolutePath, 'utf-8') + } + } else { + return fs.readFileSync(absolutePath, 'utf-8') + } + } + + for (const file of configFiles) { + const content = readConfig(file) + if (content) { + variables.configFiles = content.replace(/\r\n?/g, '\n') + break + } + } + + const cacheIdentifier = hash(variables) + return { cacheDirectory, cacheIdentifier } +} + +exports.getCwd = function () { + return process.cwd() +} + +exports.resolve = function (_path) { + return path.resolve(process.cwd(), _path) +} diff --git a/commitlint.config.js b/commitlint.config.js index 3b73464c..1c929b0f 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,3 +1,3 @@ module.exports = { extends: ['./node_modules/vue-cli-plugin-commitlint/lib/lint', '@commitlint/config-conventional'] -}; \ No newline at end of file +} diff --git a/config/eslintLoader.js b/config/eslintLoader.js new file mode 100644 index 00000000..e4cac3a9 --- /dev/null +++ b/config/eslintLoader.js @@ -0,0 +1,50 @@ +module.exports = ({ config, options, api }) => { + const { lintOnSave = 'warning' } = options + const extensions = ['js', 'jsx', 'vue'] + return () => { + const path = require('path') + const cwd = api.getCwd() + const { resolveModule, loadModule } = require('@vue/cli-shared-utils') + const allWarnings = lintOnSave === true || lintOnSave === 'warning' + const allErrors = lintOnSave === 'error' + + const eslintPkg = + loadModule('eslint/package.json', cwd, true) || + loadModule('eslint/package.json', __dirname, true) + const { cacheIdentifier } = api.genCacheConfig( + 'eslint-loader', + { + 'eslint-loader': require('eslint-loader/package.json').version, + eslint: eslintPkg.version + }, + [ + '.eslintrc.js', + '.eslintrc.yaml', + '.eslintrc.yml', + '.eslintrc.json', + '.eslintrc', + 'package.json' + ] + ) + config.module + .rule('eslint') + .pre() + .exclude.add(/node_modules/) + .end() + .test(/\.(vue|(j)sx?)$/) + .use('eslint-loader') + .loader(require.resolve('eslint-loader')) + .options({ + extensions, + cache: true, + cacheIdentifier, + emitWarning: allWarnings, + emitError: allErrors, + eslintPath: path.dirname( + resolveModule('eslint/package.json', cwd) || + resolveModule('eslint/package.json', __dirname) + ), + formatter: loadModule('eslint/lib/formatters/codeframe', cwd, true) + }) + } +} diff --git a/dist/index/1.bundle.js.map b/dist/index/1.bundle.js.map index c4287c0c..b30b105f 100644 --- a/dist/index/1.bundle.js.map +++ b/dist/index/1.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"1.bundle.js","sources":["webpack:///./src/style/index.postcss?1854"],"sourcesContent":["// extracted by mini-css-extract-plugin"],"mappings":";;;;;;;;;;AAAA;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"1.bundle.js","sources":["webpack:///./src/style/index.postcss?7470"],"sourcesContent":["// extracted by mini-css-extract-plugin"],"mappings":";;;;;;;;;;AAAA;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/dist/index/index.bundle.js b/dist/index/index.bundle.js index d023f40b..2b8cb1c2 100644 --- a/dist/index/index.bundle.js +++ b/dist/index/index.bundle.js @@ -24,9 +24,9 @@ module.exports = (__webpack_require__(/*! dll-reference ssr */ "dll-reference ss __webpack_require__.r(__webpack_exports__); /* harmony import */ var _treeShaking__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./treeShaking */ "./src/treeShaking.js"); // import TS from './ts/index.ts' + __webpack_require__.e(/*! import() */ 0).then(__webpack_require__.bind(null, /*! ./ts/index.ts */ "./src/ts/index.ts")).then(function (res) { - console.log(res); - new res.default(); + console.log(res); // new res.default() }); __webpack_require__(/*! ./style/index.css */ "./src/style/index.css"); @@ -41,7 +41,6 @@ __webpack_require__.e(/*! import() */ 1).then(__webpack_require__.t.bind(null, / __webpack_require__(/*! react */ "./node_modules/react/index.js"); - console.log(Object(_treeShaking__WEBPACK_IMPORTED_MODULE_0__[/* cube */ "a"])(2)); var h2 = document.createElement('h2'); h2.className = 'test'; diff --git a/dist/index/index.bundle.js.gz b/dist/index/index.bundle.js.gz index a221d2ad798926f75d0fa10b003dfc5cca767675..ea459daa23d3d8fc64a6965cfe051bee9881cbe3 100644 GIT binary patch literal 1081 zcmV-91jhRxiwFP!000026Wv$MZsRr(zWXV-+JhxSmQr5|#K@s-d}zCAf^32wyaqu_ z<5-DAYDp?_uxp^lUVG~^^wR4-&|;sXL;cvYE&pVj7TxBMAmni7o9`QPM)pI*L-8=Q z9$=iZ;O++{cxsKv3E8so{yiCv952n()E*8kG=iBma^JODey7v%iRJlRgg_G!W-%yV z0t>XCn|Zg&I!3b>ooD%Z(RtG%#5f}%#Bjqjgk)!QGLa%7VH|fQOh5t;fG8!2afYtm zJP$74q)50RN;4e=1ZJs_8iR|BhoszQalF{b6qM_RKzow$Ku3bxMG|gh=MqXwF{p&M zStNl{hamHXp;!4kA$EhMZNfI>j*@MxT8?Ay5z^^biq9RlCcct^pRkDU7Q3e1%8}ht zESRk_O{KVxLij9JmlTyJDBaGmh2Bt483o$vw;HTGX*W1TlKc*tGMNbeNTS3n8^-UM zBvea)*Hd;E@f%8i9(;T8&38Z2@6RsIFRuot^z8if`qh9QQHpwQlhgBSPRLS#+G?ql z?^ofkUKiJ(jfYjKr&jG&V^)xdDNfpsiE!k2dJ4R$!n`qhvw0TBE-BG11JuziSFz9v zca=QEmY@vfgam>sfn^g91hzJ);B2Vbcn-pU{wLmrA*BggI;T;^I%dwAbM5o8H)?FATE!ypFppWUAJ z+GsZIc|pvS`iUig#%&EsxAWzQbC6ds)73I#40jgp#v*+5uvP$>oc4A-p{r%JuWN2R zr)$-^zrX$aO$#qG5+zYrbTob>NyMWrqV1Ne-89Z_BEFBJ<^A11T5O@I_Bb3e2z=pG z<*&;DW7tlzir4F)vFQt^O9jtBmkR#RbgfMrd&%0MYSqC(L=`-&&wsT-$l}xe&Wb#&bQYk*{!3qAH@U@7boWV&-`VZtA?D-3ST$mP;1s5e;@vok^Z2 z*eCN{vu7+qrly}ebrz?a+H|o~{;4LJ1;4{xV{`v+VPuc;`RX!P0L-3 znuRL%Y;)XffBN;ePrv{9@xw14Km1YJna;mz^@IdGmY*&anvo8f^;`2L6rLp>fCD1{@O>Z zDVc_+Z}XdZ2iY~A@lgfISxhW*W)H>x6uZqtBB0tt+G@?+;qb_{62_wm&a#$k1=Eb* zb?Vw{l>61Zj>Lb5eFnM#q8FiH9nrXYa_K$MciI73%& zo(Gq2QY2gurJ0Tc0<%m=jlo6ELsD(CB$;pI3aWKOpgqlbpku-9G6}b~a|xxD7*xXB zJeEMILy-B>(5w9&5xd3GHep+GN6FS!EyuBU2xkXP{F>6APrg0>=DQ#1_owG)7ndi;^z`ib>eUH7pcM7oB&X*$oREb8jnzsk z-><`8zAm3Z7Z0mSPp!JGNkI{%JZL*6z=7lG2zc8C^Csxb=6RC1qyo3_-vqZ<#d}t| ztJNX41Z5Z}BoJH)yw!=gE*6Kl#^Ije-(Cn)mL~{l*m*P;aWg+kKO|7a3se)v%8s>< zAC_gUUaEC#e=PW-Hi0o)Pw=ERr=_-FYSH$qE!ygJb(@hgq4Z`P)vo1|ubpj)6(xr3 zZX(7*Is~;HJl`1{%3ci zK^M)Uffpo9sh?O1Xx!DHbhlWJIR|+OGhHt;#&BouZX&`54=)QKmC;~Z30=NdySnCD zIbFG~yZhU}-?XqIAyE>AMMskdlEyslBieqo+Ru{wI_A45T0G$0qs0cA8r5N+LEsCg zswgjejA2{JD$CbiW78K-mkOSNE*1Qr=~|gKc9OM5)v|-Vh$?wlodXYvdYdzeSy$D4 z$;vQw*w}gYxe&Wb&I>*2k*{=7p(>-U?%AfXV&+8)Zfm`v-3kf&mP_X75e>Faol9OM zI3$nTX3s=~OhunNb(W{w`gFNd{i-L=zX5_)gC2tMdoL+Hzq&Y~wCA_c#O*yCnwC4C zHA_|O+4{WM{q*Z^pML-IlPDe)9MKcc&s>GDKsNJGQ-hz0mW#x8;G&$ zt~simt-sHMC(I2gqKu#NG4`MN*xhtZ{VN3$?_@4!Irzt*Znen#1eoOIzxBE0oc)!L z*kagRFMaFZ%v;EA@Qg(jBxeb+%$Xe&|5NO?6N!Kt6KSXO=#EAQu9Y$#PjQyDTq}rj ze%rsp@l{A=jmP8S%km{rB9{T2;=GB4?CRpxQQ7t;h!P{*C@*E%U)ln|;%X8A07Bgx AX8-^I diff --git a/dist/index/index.bundle.js.map b/dist/index/index.bundle.js.map index deeb179f..0e602218 100644 --- a/dist/index/index.bundle.js.map +++ b/dist/index/index.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"index.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?cc30","webpack:///./src/style/index.css?a472","webpack:///./src/style/index.less?84c0","webpack:///./src/style/index.scss?8371","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport('./ts/index.ts').then(function (res) {\n console.log(res);\n new res.default();\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nimport { cube } from './treeShaking';\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"index.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?d30f","webpack:///./src/style/index.css?23bf","webpack:///./src/style/index.less?19b9","webpack:///./src/style/index.scss?5d75","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport { cube } from './treeShaking';\nimport('./ts/index.ts').then(function (res) {\n console.log(res); // new res.default()\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACtBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/dist/index2/1.bundle.js.map b/dist/index2/1.bundle.js.map index c4287c0c..b30b105f 100644 --- a/dist/index2/1.bundle.js.map +++ b/dist/index2/1.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"1.bundle.js","sources":["webpack:///./src/style/index.postcss?1854"],"sourcesContent":["// extracted by mini-css-extract-plugin"],"mappings":";;;;;;;;;;AAAA;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"1.bundle.js","sources":["webpack:///./src/style/index.postcss?7470"],"sourcesContent":["// extracted by mini-css-extract-plugin"],"mappings":";;;;;;;;;;AAAA;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/dist/index2/index.bundle.js.map b/dist/index2/index.bundle.js.map index deeb179f..d0b010ce 100644 --- a/dist/index2/index.bundle.js.map +++ b/dist/index2/index.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"index.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?cc30","webpack:///./src/style/index.css?a472","webpack:///./src/style/index.less?84c0","webpack:///./src/style/index.scss?8371","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport('./ts/index.ts').then(function (res) {\n console.log(res);\n new res.default();\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nimport { cube } from './treeShaking';\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"index.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?d30f","webpack:///./src/style/index.css?23bf","webpack:///./src/style/index.less?19b9","webpack:///./src/style/index.scss?5d75","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport('./ts/index.ts').then(function (res) {\n console.log(res);\n new res.default();\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nimport { cube } from './treeShaking';\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/dist/index2/index2.bundle.js.map b/dist/index2/index2.bundle.js.map index 57f7fd24..326c091b 100644 --- a/dist/index2/index2.bundle.js.map +++ b/dist/index2/index2.bundle.js.map @@ -1 +1 @@ -{"version":3,"file":"index2.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?cc30","webpack:///./src/style/index.css?a472","webpack:///./src/style/index.less?84c0","webpack:///./src/style/index.scss?8371","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport('./ts/index.ts').then(function (res) {\n console.log(res);\n new res.default();\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nimport { cube } from './treeShaking';\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file +{"version":3,"file":"index2.bundle.js","sources":["webpack:///./src/main.js","webpack:///./src/style/app.css?d30f","webpack:///./src/style/index.css?23bf","webpack:///./src/style/index.less?19b9","webpack:///./src/style/index.scss?5d75","webpack:///./src/treeShaking.js"],"sourcesContent":["// import TS from './ts/index.ts'\nimport('./ts/index.ts').then(function (res) {\n console.log(res);\n new res.default();\n});\n\nrequire('./style/index.css');\n\nrequire('./style/app.css');\n\nrequire('./style/index.less');\n\nrequire('./style/index.scss');\n\nimport('./style/index.postcss');\n\nrequire('react');\n\nimport { cube } from './treeShaking';\nconsole.log(cube(2));\nvar h2 = document.createElement('h2');\nh2.className = 'test';\nh2.innerText = 'testaaa';\ndocument.body.append(h2);","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","// extracted by mini-css-extract-plugin","import _ from 'lodash';\nexport function square(x) {\n console.log('我是一个 square');\n console.log(_);\n return x * x;\n}\nexport function cube(x) {\n console.log('我是一个 cube');\n return x * x * x;\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;ACvBA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A","sourceRoot":""} \ No newline at end of file diff --git a/options-chain-loader.js b/options-chain-loader.js index a771de8e..f391f666 100644 --- a/options-chain-loader.js +++ b/options-chain-loader.js @@ -1,15 +1,15 @@ module.exports = function(content) { - return content.replace(new RegExp(/([\$_\w\.]+\?\.)/,'g'),function(res) { - let str = res.replace(/\?\./,''); - let arrs = str.split('.'); - let strArr = []; - for(let i = 1; i <= arrs.length; i++) { - strArr.push(arrs.slice(0,i).join('.')); + return content.replace(new RegExp(/([\$_\w\.]+\?\.)/, 'g'), function(res) { + const str = res.replace(/\?\./, '') + const arrs = str.split('.') + const strArr = [] + for (let i = 1; i <= arrs.length; i++) { + strArr.push(arrs.slice(0, i).join('.')) } - let compile = strArr.join('&&'); + const compile = strArr.join('&&') const done = compile + '&&' + str + '.' - console.log(done); - - return done; - }); -}; \ No newline at end of file + console.log(done) + + return done + }) +} diff --git a/package.json b/package.json index 12504d2f..92b357f4 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,8 @@ "@babel/preset-react": "^7.7.4", "@babel/preset-typescript": "^7.6.0", "@commitlint/config-conventional": "^8.2.0", + "@typescript-eslint/parser": "^2.10.0", + "@vue/cli-shared-utils": "^4.1.1", "acorn": "^7.1.0", "autoprefixer": "^9.7.2", "babel-loader": "^8.0.6", @@ -44,11 +46,20 @@ "cross-env": "^6.0.3", "css-loader": "^3.2.0", "cssnano": "^4.1.10", + "eslint": "^6.7.2", + "eslint-config-standard": "^14.1.0", + "eslint-loader": "^3.0.3", + "eslint-plugin-import": "^2.18.2", + "eslint-plugin-node": "^10.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.1", + "eslint-plugin-vue": "^6.0.1", "express": "^4.17.1", "extract-text-webpack-plugin": "^3.0.2", "fork-ts-checker-notifier-webpack-plugin": "^1.0.2", "fork-ts-checker-webpack-plugin": "^3.1.0", "friendly-errors-webpack-plugin": "^1.7.0", + "hash-sum": "^2.0.0", "html-webpack-plugin": "^3.2.0", "husky": "^3.1.0", "less": "^3.10.3", diff --git a/packages/eslint/lint.js b/packages/eslint/lint.js new file mode 100644 index 00000000..8032f419 --- /dev/null +++ b/packages/eslint/lint.js @@ -0,0 +1,129 @@ +const fs = require('fs') +const globby = require('globby') + +const renamedArrayArgs = { + ext: 'extensions', + env: 'envs', + global: 'globals', + rulesdir: 'rulePaths', + plugin: 'plugins', + 'ignore-pattern': 'ignorePattern' +} + +const renamedArgs = { + 'inline-config': 'allowInlineConfig', + rule: 'rules', + eslintrc: 'useEslintrc', + c: 'configFile', + config: 'configFile' +} + +module.exports = function lint ({ args = {}, api }) { + const path = require('path') + const cwd = api.resolve('.') + const { log, done, exit, chalk, loadModule } = require('@vue/cli-shared-utils') + const { CLIEngine } = loadModule('eslint', cwd, true) || require('eslint') + const extensions = require('./eslintOptions').extensions(api) + + const argsConfig = normalizeConfig(args) + const config = Object.assign({ + extensions, + fix: true, + cwd + }, argsConfig) + + const noFixWarnings = (argsConfig.fixWarnings === false) + const noFixWarningsPredicate = (lintResult) => lintResult.severity === 2 + config.fix = config.fix && (noFixWarnings ? noFixWarningsPredicate : true) + + if (!fs.existsSync(api.resolve('.eslintignore')) && !config.ignorePattern) { + config.ignorePattern = [ + '!.*.js', + '!{src,tests}/**/.*.js' + ] + } + + const engine = new CLIEngine(config) + + const defaultFilesToLint = [ + 'src', + 'tests', + '*.js', + '.*.js' + ] + .filter(pattern => + globby + .sync(pattern, { cwd, absolute: true }) + .some(p => !engine.isPathIgnored(p)) + ) + + const files = args._ && args._.length + ? args._ + : defaultFilesToLint + + const processCwd = process.cwd + if (!api.invoking) { + process.cwd = () => cwd + } + const report = engine.executeOnFiles(files) + process.cwd = processCwd + + const formatter = engine.getFormatter(args.format || 'codeframe') + + if (config.fix) { + CLIEngine.outputFixes(report) + } + + const maxErrors = argsConfig.maxErrors || 0 + const maxWarnings = typeof argsConfig.maxWarnings === 'number' ? argsConfig.maxWarnings : Infinity + const isErrorsExceeded = report.errorCount > maxErrors + const isWarningsExceeded = report.warningCount > maxWarnings + + if (!isErrorsExceeded && !isWarningsExceeded) { + if (!args.silent) { + const hasFixed = report.results.some(f => f.output) + if (hasFixed) { + log('Eslint 正在帮您修复以下文件...') + log() + report.results.forEach(f => { + if (f.output) { + log(` ${chalk.blue(path.relative(cwd, f.filePath))}`) + } + }) + log() + } + if (report.warningCount || report.errorCount) { + console.log(formatter(report.results)) + } else { + done(hasFixed ? '所有错误被自动修复' : 'eslint 没有发现错误!') + } + } + } else { + console.log(formatter(report.results)) + if (isErrorsExceeded && typeof argsConfig.maxErrors === 'number') { + log(`Eslint 发现太多错误 (maximum: ${argsConfig.maxErrors}).`) + } + if (isWarningsExceeded) { + log(`Eslint 发现太多错误 (maximum: ${argsConfig.maxWarnings}).`) + } + exit(1) + } +} + +function normalizeConfig (args) { + const config = {} + for (const key in args) { + if (renamedArrayArgs[key]) { + config[renamedArrayArgs[key]] = args[key].split(',') + } else if (renamedArgs[key]) { + config[renamedArgs[key]] = args[key] + } else if (key !== '_') { + config[camelize(key)] = args[key] + } + } + return config +} + +function camelize (str) { + return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : '')) +} diff --git a/packages/stylelint/index.js b/packages/stylelint/index.js new file mode 100644 index 00000000..ebf51359 --- /dev/null +++ b/packages/stylelint/index.js @@ -0,0 +1,42 @@ +const StyleLintPlugin = require('stylelint-webpack-plugin') +const CodeframeFormatter = require('stylelint-codeframe-formatter') + +module.exports = (api, projectOptions) => { + const { pluginOptions: { lintOnSave, stylelint } } = projectOptions + if (lintOnSave) { + api.chainWebpack((webpackConfig) => { + webpackConfig + .plugin('stylelint') + .use(StyleLintPlugin, [Object.assign({ + failOnError: lintOnSave === 'error', + files: ['src/**/*.{vue,htm,html,css,sss,less,scss}'], + formatter: CodeframeFormatter + }, stylelint)]) + .end() + .plugin('friendly-errors') + .tap(([options]) => { + ['Transformers', 'Formatters'].forEach((name) => { + const optKey = `additional${name}` + let plugins + if (Array.isArray(options[optKey])) { + plugins = options[optKey] + } else { + plugins = [] + Object.assign(options, { [optKey]: plugins }) + } + + let plugin + try { + const pluginName = name.toLowerCase().slice(0, -1) + plugin = require('./stylelintError')[pluginName] + } catch (e) { + return + } + + plugin && plugins.push(plugin) + }) + return [options] + }) + }) + } +} diff --git a/packages/stylelint/lint.js b/packages/stylelint/lint.js new file mode 100644 index 00000000..6003b804 --- /dev/null +++ b/packages/stylelint/lint.js @@ -0,0 +1,104 @@ +const { execSync } = require('child_process') +const chalk = require('chalk') +const stylelint = require('stylelint') +const CodeframeFormatter = require('stylelint-codeframe-formatter') +function camelize(str) { + return str.replace(/-(\w)/g, (_, c) => ( + c + ? c.toUpperCase() + : '' + )) +} + +function normalizeConfig(args) { + const config = {} + Object.keys(args).forEach((key) => { + if (key !== '_') { + config[camelize(key)] = args[key] + } + }) + return config +} + +function format(label, msg) { + let lines = msg.split('\n') + lines = lines.map((line, idx) => ( + idx === 0 + ? `${label} ${line}` + : line.padStart(chalk.reset(label).length) + )) + + return lines.join('\n') +} + +module.exports = async function lint({ api, args = {}, pluginOptions = {} }) { + if (args.options) { + execSync('stylelint --help', { stdio: 'inherit' }) + return + } + + const cwd = api.resolve('.') + + const files = args._ && args._.length ? args._ : [cwd + '/src/**/*.{vue,htm,html,css,sss,less,scss}'] + if (args['no-fix']) { + args.fix = false + delete args['no-fix'] + } + + const { formatter } = args + if ( + formatter && + typeof formatter === 'string' && + !(['json', 'string', 'verbose'].includes(formatter)) + ) { + try { + args.formatter = require(formatter) + } catch (e) { + delete args.formatter + if (typeof pluginOptions.formatter !== 'function') { + console.log(format( + chalk`{bgYellow.black WARN }`, + chalk`${e.toString()}\n{yellow Invalid formatter}` + )) + } + } + } + + const options = Object.assign({}, { + configBasedir: cwd, + fix: true, + files, + formatter: CodeframeFormatter + }, pluginOptions, normalizeConfig(args)) + + try { + const { errored, results, output: formattedOutput } = await stylelint.lint(options) + if (!errored) { + if (!args.silent) { + const hasWarnings = results.some((result) => { + if (result.ignored) { + return null + } + return result.warnings.some(warning => warning.severity === 'warning') + }) + if (hasWarnings) { + console.log(formattedOutput) + } else { + console.log(format( + chalk`{bgGreen.black DONE }`, + `stylelint 没有发现错误!${options.fix ? chalk` {blue (autofix enabled)}` : ''}` + )) + } + } + } else { + console.log(formattedOutput) + process.exit(1) + } + } catch (err) { + console.log(format( + chalk`{bgRed.black ERROR }`, + err.stack.slice(' Error:'.length) + )) + process.exit(1) + } +} diff --git a/packages/stylelint/stylelintError.js b/packages/stylelint/stylelintError.js new file mode 100644 index 00000000..93d259b1 --- /dev/null +++ b/packages/stylelint/stylelintError.js @@ -0,0 +1,38 @@ +const chalk = require('chalk') + +const TYPE = 'stylelint-error' + +exports.transformer = (error) => { + const { originalStack } = error + const match = originalStack.some(({ fileName }) => ( + fileName && + fileName.indexOf('stylelint-webpack-plugin') > 0 + )) + if (match) { + return Object.assign({}, error, { type: TYPE }) + } + return error +} + +function severityColor(severity) { + switch (severity.toLowerCase()) { + case 'success': return 'green' + case 'info': return 'blue' + case 'note': return 'white' + case 'warning': return 'yellow' + case 'error': return 'red' + default: return 'red' + } +} + +exports.formatter = (errors, severity) => { + errors = errors.filter(e => e.type === TYPE) + if (errors.length > 0) { + return [ + '', + chalk`{bgMagenta.white stylelint } {${severityColor(severity)} ${severity}}`, + ...errors.map(({ message }) => message) + ] + } + return [] +} diff --git a/packages/stylelint/utils.js b/packages/stylelint/utils.js new file mode 100644 index 00000000..c014f64c --- /dev/null +++ b/packages/stylelint/utils.js @@ -0,0 +1,18 @@ +const micromatch = require('micromatch') +const fs = require('fs') + +function getDirectoryEntries(directory) { + try { + return fs.readdirSync(directory) + } catch (e) { + return [] + } +} + +exports.hasStylelintConfig = function hasESLintConfig(directory) { + return micromatch.some( + getDirectoryEntries(directory), + ['stylelint.config.js', '.stylelintrc', '.stylelintrc.{js,json,yaml,yml}'], + { dot: true } + ) +} diff --git a/packages/tslint/generator/index.js b/packages/tslint/generator/index.js new file mode 100644 index 00000000..0c0c42d5 --- /dev/null +++ b/packages/tslint/generator/index.js @@ -0,0 +1 @@ +module.exports = () => {} diff --git a/packages/tslint/index.js b/packages/tslint/index.js new file mode 100644 index 00000000..e915ffa5 --- /dev/null +++ b/packages/tslint/index.js @@ -0,0 +1,18 @@ +module.exports = (api, options = {}) => { + const fs = require('fs') + const useThreads = process.env.NODE_ENV === 'production' && !!options.parallel + const { pluginOptions: { lintOnSave } } = options + api.chainWebpack(config => { + if (lintOnSave) { + config + .plugin('fork-ts-checker') + .use(require('fork-ts-checker-webpack-plugin'), [{ + vue: true, + tslint: lintOnSave !== false && fs.existsSync(api.resolve('tslint.json')), + formatter: 'codeframe', + // https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse + checkSyntacticErrors: useThreads + }]) + } + }) +} diff --git a/packages/tslint/lint.js b/packages/tslint/lint.js new file mode 100644 index 00000000..1459c867 --- /dev/null +++ b/packages/tslint/lint.js @@ -0,0 +1,134 @@ +const { done } = require('@vue/cli-shared-utils') + +module.exports = function lint ({ args = {}, api, silent }) { + const cwd = api.resolve('.') + const fs = require('fs') + const path = require('path') + const globby = require('globby') + const tslint = require('tslint') + const ts = require('typescript') + const vueCompiler = require('vue-template-compiler') + const isVueFile = file => /\.vue(\.ts)?$/.test(file) + + const options = { + fix: args.fix !== false, + formatter: args.format || 'codeFrame', + formattersDirectory: args['formatters-dir'], + rulesDirectory: args['rules-dir'] + } + + const vueFileCache = new Map() + const writeFileSync = fs.writeFileSync + + const patchWriteFile = () => { + fs.writeFileSync = (file, content, options) => { + if (isVueFile(file)) { + const parts = vueFileCache.get(path.normalize(file)) + if (parts) { + parts.content = content + const { before, after } = parts + content = `${before}\n${content.trim()}\n${after}` + } + } + return writeFileSync(file, content, options) + } + } + + const restoreWriteFile = () => { + fs.writeFileSync = writeFileSync + } + + const parseTSFromVueFile = file => { + if (vueFileCache.has(file)) { + return vueFileCache.get(file) + } + + const content = fs.readFileSync(file, 'utf-8') + const { script } = vueCompiler.parseComponent(content, { pad: 'line' }) + if (script && /^tsx?$/.test(script.lang)) { + vueFileCache.set(file, { + before: content.slice(0, script.start), + after: content.slice(script.end), + content: script.content + }) + return script + } + } + + const program = tslint.Linter.createProgram(api.resolve('tsconfig.json')) + + const patchProgram = program => { + const getSourceFile = program.getSourceFile + program.getSourceFile = function (file, languageVersion, onError) { + if (isVueFile(file)) { + const { content, lang = 'js' } = parseTSFromVueFile(file) || { content: '', lang: 'js' } + const contentLang = ts.ScriptKind[lang.toUpperCase()] + return ts.createSourceFile(file, content, languageVersion, true, contentLang) + } else { + return getSourceFile.call(this, file, languageVersion, onError) + } + } + } + + patchProgram(program) + + const linter = new tslint.Linter(options, program) + + const updateProgram = linter.updateProgram + linter.updateProgram = function (...args) { + updateProgram.call(this, ...args) + patchProgram(this.program) + } + + const tslintConfigPath = tslint.Configuration.CONFIG_FILENAMES + .map(filename => api.resolve(filename)) + .find(file => fs.existsSync(file)) + + const config = tslint.Configuration.findConfiguration(tslintConfigPath).results + const vueConfig = Object.assign(config) + const rules = vueConfig.rules = new Map(vueConfig.rules) + const rule = rules.get('no-consecutive-blank-lines') + rules.set('no-consecutive-blank-lines', Object.assign({}, rule, { + ruleSeverity: 'off' + })) + + const lint = file => { + const filePath = api.resolve(file) + const isVue = isVueFile(file) + patchWriteFile() + linter.lint( + filePath, + '', + isVue ? vueConfig : config + ) + restoreWriteFile() + } + + const files = args._ && args._.length + ? args._ + : [cwd + '/src/**/*.ts', cwd + '/src/**/*.vue', cwd + '/src/**/*.tsx'] + + if (config.linterOptions && config.linterOptions.exclude) { + const rawTslintConfig = tslint.Configuration.readConfigurationFile(tslintConfigPath) + const excludedGlobs = rawTslintConfig.linterOptions.exclude + excludedGlobs.forEach((g) => files.push('!' + g)) + } + + return globby(files, { cwd }).then(files => { + files.forEach(lint) + if (silent) return + const result = linter.getResult() + if (result.output.trim()) { + process.stdout.write(result.output) + } else if (result.fixes.length) { + const f = new tslint.Formatters.ProseFormatter() + process.stdout.write(f.format(result.failures, result.fixes)) + } else if (!result.failures.length) { + done('tslint 没有发现错误.\n') + } + + if (result.failures.length && !args.force) { + process.exitCode = 1 + } + }) +} diff --git a/packages/tslint/prompts.js b/packages/tslint/prompts.js new file mode 100644 index 00000000..d7faf17f --- /dev/null +++ b/packages/tslint/prompts.js @@ -0,0 +1 @@ +module.exports = [] diff --git a/src/main.js b/src/main.js index 5e07f89c..a3f7deb4 100644 --- a/src/main.js +++ b/src/main.js @@ -1,22 +1,20 @@ // import TS from './ts/index.ts' +import { cube } from './treeShaking' + import('./ts/index.ts').then(res => { console.log(res) - new res.default() -}); - + // new res.default() +}) require('./style/index.css') require('./style/app.css') require('./style/index.less') require('./style/index.scss') -import('./style/index.postcss'); - +import('./style/index.postcss') require('react') -import { cube, square } from './treeShaking'; - -console.log(cube(2)) +console.log(cube(2)) const h2 = document.createElement('h2') h2.className = 'test' h2.innerText = 'testaaa' -document.body.append(h2); \ No newline at end of file +document.body.append(h2) diff --git a/src/ssr.jsx b/src/ssr.jsx index 8c174a69..3edec6d3 100644 --- a/src/ssr.jsx +++ b/src/ssr.jsx @@ -1,13 +1,12 @@ -const React = require("react"); -const ReactDOM = require("react-dom"); +const ReactDOM = require('react-dom') -const SSR =
alert("hello")}>Hello world
; +const SSR =
alert('hello')}>Hello world
-if (typeof document === "undefined") { +if (typeof document === 'undefined') { console.log('在服务端渲染') - module.exports = SSR; + module.exports = SSR } else { console.log('在客户端渲染') - const renderMethod = !module.hot ? ReactDOM.render : ReactDOM.hydrate; - renderMethod(SSR, document.getElementById("app")); -} \ No newline at end of file + const renderMethod = !module.hot ? ReactDOM.render : ReactDOM.hydrate + renderMethod(SSR, document.getElementById('app')) +} diff --git a/src/treeShaking.js b/src/treeShaking.js index 97925a7b..18184363 100644 --- a/src/treeShaking.js +++ b/src/treeShaking.js @@ -3,10 +3,10 @@ import _ from 'lodash' export function square(x) { console.log('我是一个 square') console.log(_) - return x * x; + return x * x } export function cube(x) { console.log('我是一个 cube') - return x * x * x; -} \ No newline at end of file + return x * x * x +} diff --git a/webapck-plugin-copy.js b/webapck-plugin-copy.js index d77ef527..cab2d844 100644 --- a/webapck-plugin-copy.js +++ b/webapck-plugin-copy.js @@ -3,13 +3,14 @@ const globby = require('globby') class CopyDirWebpackPlugin { constructor(options) { - this.options = options; + this.options = options } + apply(compiler) { const opt = this.options compiler.plugin('done', (stats) => { if (process.env.NODE_ENV === 'production') { - (async ()=>{ + (async () => { const toFilesPath = await globby([`${opt.to}/**`, '!.git/**']) toFilesPath.forEach(filePath => fs.removeSync(filePath)) const fromFilesPath = await globby([`${opt.from}/**`]) @@ -23,8 +24,8 @@ class CopyDirWebpackPlugin { console.log(` 完成copy ${opt.from} to ${opt.to}`) })() } - }); + }) } } -module.exports = CopyDirWebpackPlugin \ No newline at end of file +module.exports = CopyDirWebpackPlugin