Skip to content

Commit

Permalink
feat(cli): 尝试接入 webpack 来编译各端小程序
Browse files Browse the repository at this point in the history
  • Loading branch information
luckyadam committed Dec 31, 2019
1 parent b0ec706 commit 338650a
Show file tree
Hide file tree
Showing 11 changed files with 5,019 additions and 0 deletions.
40 changes: 40 additions & 0 deletions packages/taro-cli/src/mini/webpack.ts
@@ -0,0 +1,40 @@
import * as fs from 'fs-extra'
import * as path from 'path'

import { IMiniAppBuildConfig } from '../util/types'
import { BUILD_TYPES } from '../util/constants'
import * as npmProcess from '../util/npm'

import {
setBuildData,
setIsProduction,
getBuildData
} from './helper'

export async function build (appPath: string, { watch, adapter = BUILD_TYPES.WEAPP, envHasBeenSet = false, port, release }: IMiniAppBuildConfig) {
const buildData = setBuildData(appPath, adapter)
const isQuickApp = adapter === BUILD_TYPES.QUICKAPP
process.env.TARO_ENV = adapter
if (!envHasBeenSet) {
setIsProduction(process.env.NODE_ENV === 'production' || !watch)
}
fs.ensureDirSync(buildData.outputDir)

await buildWithWebpack({
appPath
})

}

async function buildWithWebpack ({ appPath }: { appPath: string }) {
const { entryFilePath, outputDir, sourceDir } = getBuildData()
console.log(entryFilePath, outputDir)
const miniRunner = await npmProcess.getNpmPkg('@tarojs/mini-runner', appPath)
const miniRunnerOpts = {
entry: {
app: entryFilePath
},
outputDir
}
miniRunner(miniRunnerOpts)
}
2 changes: 2 additions & 0 deletions packages/taro-mini-runner/index.js
@@ -0,0 +1,2 @@
module.exports = require('./dist/index.js').default
module.exports.default = module.exports
4 changes: 4 additions & 0 deletions packages/taro-mini-runner/jest.config.js
@@ -0,0 +1,4 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
}
53 changes: 53 additions & 0 deletions packages/taro-mini-runner/package.json
@@ -0,0 +1,53 @@
{
"name": "@tarojs/mini-runner",
"version": "1.3.0-beta.2",
"description": "Mini app runner for taro",
"main": "index.js",
"scripts": {
"build": "run-s clean prod",
"dev": "tsc -w",
"prod": "tsc",
"clean": "rimraf dist",
"lint": "tslint src/**/*.ts --fix",
"lint:typecheck": "tslint -p tsconfig.json src/**/*.ts --fix",
"prepack": "npm run build",
"test": "jest",
"test:dev": "jest --watch"
},
"repository": {
"type": "git",
"url": "git+https://github.com/NervJS/taro.git"
},
"files": [
"index.js",
"dist"
],
"keywords": [
"taro"
],
"author": "luckyadam",
"license": "MIT",
"bugs": {
"url": "https://github.com/NervJS/taro/issues"
},
"homepage": "https://github.com/NervJS/taro#readme",
"devDependencies": {
"@types/node": "^12.0.0",
"jest": "^24.8.0",
"npm-run-all": "^4.1.5",
"ts-jest": "^24.0.2",
"typescript": "^3.4.5"
},
"dependencies": {
"@types/lodash": "^4.14.126",
"@types/webpack": "^4.4.31",
"babel-core": "^6.26.3",
"babel-loader": "^8.0.6",
"chalk": "^2.4.2",
"lodash": "^4.17.11",
"ora": "^3.4.0",
"webpack": "^4.31.0",
"webpack-chain": "^6.0.0",
"webpack-format-messages": "^2.0.5"
}
}
28 changes: 28 additions & 0 deletions packages/taro-mini-runner/src/index.ts
@@ -0,0 +1,28 @@
import * as webpack from 'webpack'

import { IBuildConfig } from './utils/types'
import { printBuildError, bindProdLogger } from './utils/logHelper'
import MiniPlugin from './plugins/miniPlugin'

export default function build (config: IBuildConfig) {
const webpackConfig = {
entry: config.entry,
output: {
filename: '[name].js',
publicPath: '/',
path: config.outputDir,
},
plugins: [
new MiniPlugin()
]
}

const compiler = webpack(webpackConfig)
bindProdLogger(compiler)

compiler.run((err) => {
if (err) {
printBuildError(err)
}
})
}
60 changes: 60 additions & 0 deletions packages/taro-mini-runner/src/plugins/miniPlugin.ts
@@ -0,0 +1,60 @@
import * as path from 'path'

import * as webpack from 'webpack'
import { defaults } from 'lodash'

interface IMiniPluginOptions {
appEntry?: string
}

export default class MiniPlugin {
options: IMiniPluginOptions
appEntry: string

constructor (options = {}) {
this.options = defaults(options || {}, {

})
}

try = handler => async (arg, callback) => {
try {
await handler(arg)
callback()
} catch (err) {
callback(err)
}
}

apply (compiler: webpack.Compiler) {
compiler.hooks.run.tapAsync(
'MiniPlugin run',
this.try(async (compiler: webpack.Compiler) => {
await this.run(compiler)
})
)
}

getAppEntry (compiler) {
if (this.options.appEntry) {
return this.options.appEntry
}
const { entry } = compiler.options
function getEntryPath (entry) {
if (Array.isArray(entry)) {
return entry.map(item => getEntryPath[item]).find(item => item)
}
if (typeof entry === 'object') {
return entry['app']
}
return entry
}
const appEntryPath = getEntryPath(entry)
return appEntryPath
}

run (compiler) {
this.appEntry = this.getAppEntry(compiler)
console.log(this.appEntry)
}
}
165 changes: 165 additions & 0 deletions packages/taro-mini-runner/src/utils/logHelper.ts
@@ -0,0 +1,165 @@
import chalk from 'chalk';
import * as ora from 'ora';
import { partial, pipe } from 'lodash/fp';
import * as formatMessages from 'webpack-format-messages';

// const syntaxErrorLabel = 'Syntax error:';

const getServeSpinner = (() => {
let spinner
return () => {
if (!spinner) spinner = ora(`Starting development server, please wait~`)
return spinner
}
})()

const printCompiling = () => {
getServeSpinner().text = 'Compiling...'
getServeSpinner().start()
}

const printBuildError = (err: Error): void => {
const message = err.message
const stack = err.stack
if (stack && message.indexOf('from UglifyJs') !== -1) {
try {
const matched = /(.+)\[(.+):(.+),(.+)\]\[.+\]/.exec(stack)
if (!matched) {
throw new Error('Using errors for control flow is bad.')
}
const problemPath = matched[2]
const line = matched[3]
const column = matched[4]
console.log('Failed to minify the code from this file: \n\n', chalk.yellow(`\t${problemPath}:${line}${column !== '0' ? ':' + column : ''}`), '\n')
} catch (ignored) {
console.log('Failed to minify the bundle.', err)
}
} else {
console.log((message || err) + '\n')
}
console.log()
}

const printSuccess = () => {
getServeSpinner().stopAndPersist({
symbol: '✅ ',
text: chalk.green('Compiled successfully!\n')
})
}

const printWarning = () => {
getServeSpinner().stopAndPersist({
symbol: '⚠️ ',
text: chalk.yellow('Compiled with warnings.\n')
})
}

const printFailed = () => {
getServeSpinner().stopAndPersist({
symbol: '🙅 ',
text: chalk.red('Failed to compile.\n')
})
}

const printWhenBeforeCompile = compiler => {
compiler.hooks.beforeCompile.tap('taroBeforeCompile', filepath => {
printCompiling()
})
return compiler
}

const printWhenInvalid = compiler => {
compiler.hooks.invalid.tap('taroInvalid', filepath => {
printCompiling()
})
return compiler
}

const printWhenFailed = compiler => {
compiler.hooks.failed.tap('taroFailed', error => {
printBuildError(error)
})
return compiler
}

let isFirst = true
const printWhenFirstDone = (devUrl, compiler) => {
compiler.hooks.done.tap('taroDone', stats => {
if (isFirst) {
isFirst = false
getServeSpinner().clear()
console.log()
console.log(chalk.cyan(`ℹ️ Listening at ${devUrl}`))
console.log(chalk.gray('\n监听文件修改中...\n'))
}
})
return compiler
}

const _printWhenDone = ({
verbose = false
}, compiler) => {
compiler.hooks.done.tap('taroDone', stats => {
const { errors, warnings } = formatMessages(stats)

if (!stats.hasErrors() && !stats.hasWarnings()) {
printSuccess()
}

if (stats.hasErrors()) {
printFailed()
errors.forEach(e => console.log(e + '\n'));
verbose && process.exit(1)
return;
}

if (stats.hasWarnings()) {
printWarning()
warnings.forEach(w => console.log(w + '\n'));
}

verbose && console.log(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
warnings: verbose
}) + '\n')
})
return compiler
}

const printWhenDone = partial(_printWhenDone, [{ verbose: false }])

const printWhenDoneVerbosely = partial(_printWhenDone, [{ verbose: true }])

const bindDevLogger = (devUrl, compiler) => {
console.log()
pipe(
printWhenBeforeCompile,
partial(printWhenFirstDone, [devUrl]),
printWhenDone,
printWhenFailed,
printWhenInvalid
)(compiler)
return compiler
}

const bindProdLogger = (compiler) => {
console.log()
pipe(
printWhenBeforeCompile,
printWhenDoneVerbosely,
printWhenFailed
)(compiler)
return compiler
}

export {
printBuildError,
printCompiling,
getServeSpinner,
bindDevLogger,
bindProdLogger
}

0 comments on commit 338650a

Please sign in to comment.