作者 Karson

新增JS、CSS控制台一键压缩功能

移除原有JS、CSS压缩方式
<?php
namespace app\admin\command;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\Output;
use think\Exception;
class Min extends Command
{
/**
* 路径和文件名配置
*/
protected $options = [
'cssBaseUrl' => 'public/assets/css/',
'cssBaseName' => '{module}',
'jsBaseUrl' => 'public/assets/js/',
'jsBaseName' => 'require-{module}',
];
protected function configure()
{
$this
->setName('min')
->addOption('module', 'm', Option::VALUE_REQUIRED, 'module name(frontend or backend),use \'all\' when build all modules', null)
->addOption('resource', 'r', Option::VALUE_REQUIRED, 'resource name(js or css),use \'all\' when build all resources', null)
->setDescription('Compress js and css file');
}
protected function execute(Input $input, Output $output)
{
$module = $input->getOption('module') ? : '';
$resource = $input->getOption('resource') ? : '';
if (!$module || !in_array($module, ['frontend', 'backend', 'all']))
{
throw new Exception('Please input correct module name');
}
if (!$resource || !in_array($resource, ['js', 'css', 'all']))
{
throw new Exception('Please input correct resource name');
}
$moduleArr = $module == 'all' ? ['frontend', 'backend'] : [$module];
$resourceArr = $resource == 'all' ? ['js', 'css'] : [$resource];
$minPath = __DIR__ . DS . 'Min' . DS;
$publicPath = ROOT_PATH . 'public' . DS;
$tempFile = $minPath . 'temp.js';
try
{
$nodeExec = exec("which node");
if (!$nodeExec)
{
throw new Exception("node environment not found!please install node first!");
}
}
catch (Exception $e)
{
throw new Exception($e->getMessage());
}
foreach ($moduleArr as $mod)
{
foreach ($resourceArr as $res)
{
$data = [
'publicPath' => $publicPath,
'jsBaseName' => str_replace('{module}', $mod, $this->options['jsBaseName']),
'jsBaseUrl' => $this->options['jsBaseUrl'],
'cssBaseName' => str_replace('{module}', $mod, $this->options['cssBaseName']),
'cssBaseUrl' => $this->options['cssBaseUrl'],
'jsBasePath' => ROOT_PATH . $this->options['jsBaseUrl'],
'cssBasePath' => ROOT_PATH . $this->options['cssBaseUrl'],
'ds' => DS,
];
//源文件
$from = $data["{$res}BasePath"] . $data["{$res}BaseName"] . '.' . $res;
if (!is_file($from))
{
$output->error("{$res} source file not found!file:{$from}");
continue;
}
if ($res == "js")
{
$content = file_get_contents($from);
preg_match("/require\.config\(\{[\n]+(.*?)\n\}\);/is", $content, $matches);
if (!isset($matches[1]))
{
$output->error("js config not found!");
continue;
}
$config = preg_replace("/(urlArgs|baseUrl):(.*)\n/", '', $matches[1]);
$data['config'] = $config;
}
// 生成压缩文件
$this->writeToFile($res, $data, $tempFile);
$output->info("Compress " . $data["{$res}BaseName"] . ".{$res}");
// 执行压缩
echo exec("{$nodeExec} {$minPath}r.js -o {$tempFile} >> {$minPath}node.log");
}
}
@unlink($tempFile);
$output->info("Build Successed!");
}
/**
* 写入到文件
* @param string $name
* @param array $data
* @param string $pathname
* @return mixed
*/
protected function writeToFile($name, $data, $pathname)
{
$search = $replace = [];
foreach ($data as $k => $v)
{
$search[] = "{%{$k}%}";
$replace[] = $v;
}
$stub = file_get_contents($this->getStub($name));
$content = str_replace($search, $replace, $stub);
if (!is_dir(dirname($pathname)))
{
mkdir(strtolower(dirname($pathname)), 0755, true);
}
return file_put_contents($pathname, $content);
}
/**
* 获取基础模板
* @param string $name
* @return string
*/
protected function getStub($name)
{
return __DIR__ . '/Min/stubs/' . $name . '.stub';
}
}
... ...
({
cssIn: "{%cssBasePath%}{%cssBaseName%}.css",
out: "{%cssBasePath%}{%cssBaseName%}.min.css",
optimizeCss: "default"
})
\ No newline at end of file
... ...
({
{%config%}
,
optimizeCss: "standard",
optimize: "none",
removeCombined: false,
baseUrl: "{%jsBasePath%}", //JS文件所在的基础目录
name: "{%jsBaseName%}", //来源文件,不包含后缀
out: "{%jsBasePath%}{%jsBaseName%}.min.js" //目标文件
});
\ No newline at end of file
... ...
... ... @@ -27,7 +27,7 @@ class Dashboard extends Backend
$paylist[$day] = mt_rand(1, mt_rand(1, $createlist[$day]));
}
$this->view->assign([
'totaluser' => 3500,
'totaluser' => 35200,
'totalviews' => 219390,
'totalorder' => 32143,
'totalorderamount' => 174800,
... ...
... ... @@ -4,7 +4,7 @@
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<!-- Loading Bootstrap -->
<link href="__CDN__/assets/{$Think.config.app_debug?'build/backend':'css/backend.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
<link href="__CDN__/assets/css/backend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
<!-- HTML5 shim, for IE6-8 support of HTML5 elements. All other JS at the end of file. -->
<!--[if lt IE 9]>
... ...
... ... @@ -14,4 +14,5 @@ return [
'app\admin\command\Crud',
'app\admin\command\Menu',
'app\admin\command\Install',
'app\admin\command\Min',
];
... ...
<?php
namespace app\common\model;
use think\Model;
/**
... ...
... ... @@ -7,7 +7,7 @@
<meta name="description" content="基于ThinkPHP5和Bootstrap的极速后台开发系统">
<link rel="shortcut icon" href="__CDN__/assets/img/favicon.ico" />
<!-- Loading Bootstrap -->
<link href="__CDN__/assets/{$Think.config.app_debug?'build/frontend':'css/frontend.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
<link href="__CDN__/assets/css/frontend{$Think.config.app_debug?'':'.min'}.css?v={$Think.config.site.version}" rel="stylesheet">
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
... ...
({
cssIn: 'backend.css',
out: '../css/backend.min.css',
optimizeCss: 'default'
})
\ No newline at end of file
({
baseUrl: '../js',
optimizeCss: 'standard',
optimize: 'none',
removeCombined: false,
name: "require-backend",
include: ['css', 'layer', 'toastr', 'backend', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs'],
out: "../js/require-backend.min.js",
packages: [{
name: 'moment',
location: '../libs/moment',
main: 'moment'
}],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
'bootstrap-switch': 'bootstrap-switch',
'form': 'require-form',
'table': 'require-table',
'upload': 'require-upload',
'drag': 'jquery.drag.min',
'drop': 'jquery.drop.min',
'echarts-theme': 'echarts-theme',
'adminlte': 'adminlte',
//
// 以下的包从bower的libs目录加载
'jquery': '../libs/jquery/dist/jquery.min',
'bootstrap': '../libs/bootstrap/dist/js/bootstrap.min',
'bootstrap-validator': '../libs/bootstrap-validator/dist/validator.min',
'bootstrap-typeahead': '../libs/bootstrap3-typeahead/bootstrap3-typeahead.min',
'bootstrap-tagsinput': '../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput.min',
'bootstrap-dialog': '../libs/bootstrap3-dialog/dist/js/bootstrap-dialog.min',
'bootstrap-datetimepicker': '../libs/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min',
'bootstrap-select': '../libs/bootstrap-select/dist/js/bootstrap-select.min',
'bootstrap-table': '../libs/bootstrap-table/dist/bootstrap-table.min',
'bootstrap-table-export': '../libs/bootstrap-table/dist/extensions/export/bootstrap-table-export.min',
'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile',
'bootstrap-table-advancedsearch': 'bootstrap-table-advancedsearch',
'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN',
'typeahead': '../libs/typeahead.js/dist/typeahead.jquery.min',
'bloodhound': '../libs/typeahead.js/dist/bloodhound.min',
'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min',
'dropzone': '../libs/dropzone/dist/min/dropzone-amd-module.min',
'less': '../libs/less/dist/less.min',
'dragsort': '../libs/dragsort/jquery.dragsort',
'sortable': '../libs/Sortable/Sortable.min',
'addtabs': '../libs/jquery-addtabs/jquery.addtabs',
'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll',
'crontab': '../libs/jqcron/src/jqCron.cn',
'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min',
'validator': '../libs/nice-validator/dist/local/zh-CN',
'plupload': '../libs/plupload/js/plupload.min',
'toastr': '../libs/toastr/toastr',
'jstree': '../libs/jstree/dist/jstree.min',
'layer': '../libs/layer/src/layer',
'echarts': '../libs/echarts/dist/echarts.min',
'cookie': '../libs/jquery.cookie/jquery.cookie',
'template': '../libs/art-template/dist/template-native',
},
// shim依赖配置
shim: {
'bootstrap': ['jquery'],
'bootstrap-table': {
deps: ['bootstrap', 'css!../libs/bootstrap-table/dist/bootstrap-table.min.css'],
exports: '$.fn.bootstrapTable'
},
'bootstrap-table-lang': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-export': {
deps: ['bootstrap-table', 'tableexport'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-mobile': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-advancedsearch': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'tableexport': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'slimscroll': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'adminlte': {
deps: ['bootstrap', 'slimscroll'],
exports: '$.AdminLTE'
},
'typeahead': {
deps: ['jquery'],
init: function ($) {
return require.s.contexts._.registry['typeahead.js'].factory($);
}
},
'crontab': ['../libs/jqcron/src/jqCron', 'css!../libs/jqcron/src/jqCron.css'],
'bootstrap-checkbox': ['jquery'],
'bootstrap-radio': ['jquery'],
'bootstrap-switch': ['jquery'],
'bootstrap-dialog': ['css!../libs/bootstrap3-dialog/dist/css/bootstrap-dialog.min.css'],
'bootstrap-datetimepicker': [
'css!../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css',
'moment/locale/zh-cn'
],
'bootstrap-tagsinput': [
'css!../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput-typeahead.css',
'css!../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput.css',
'jquery',
'typeahead'
],
'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ],
'summernote': ['../libs/summernote/dist/summernote.min', 'css!../libs/summernote/dist/summernote.css'],
// 'toastr': ['css!../libs/toastr/toastr.min.css'],
'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ],
'plupload': {
deps: [
'../libs/plupload/js/moxie.min'
],
exports: "plupload"
},
// 'layer': ['css!../libs/layer/build/skin/default/layer.css'],
validator: {
deps: ['../libs/nice-validator/dist/jquery.validator', 'css!../libs/nice-validator/dist/jquery.validator.css']
}
},
map: {
'*': {
'css': '../libs/require-css/css.min'
}
},
charset: 'utf-8' // 文件编码
});
\ No newline at end of file
({
cssIn: 'frontend.css',
out: '../css/frontend.min.css',
optimizeCss: 'default'
})
\ No newline at end of file
({
baseUrl: '../js',
optimizeCss: 'standard',
optimize: 'none',
removeCombined: false,
name: "require-frontend",
include: ['css', 'layer', 'toastr', 'frontend'],
out: "../js/require-frontend.min.js",
packages: [{
name: 'moment',
location: '../libs/moment',
main: 'moment'
}],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
'bootstrap-switch': 'bootstrap-switch',
'form': 'require-form',
'table': 'require-table',
'upload': 'require-upload',
'drag': 'jquery.drag.min',
'drop': 'jquery.drop.min',
'echarts-theme': 'echarts-theme',
'adminlte': 'adminlte',
//
// 以下的包从bower的libs目录加载
'jquery': '../libs/jquery/dist/jquery.min',
'bootstrap': '../libs/bootstrap/dist/js/bootstrap.min',
'bootstrap-validator': '../libs/bootstrap-validator/dist/validator.min',
'bootstrap-typeahead': '../libs/bootstrap3-typeahead/bootstrap3-typeahead.min',
'bootstrap-tagsinput': '../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput.min',
'bootstrap-dialog': '../libs/bootstrap3-dialog/dist/js/bootstrap-dialog.min',
'bootstrap-datetimepicker': '../libs/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min',
'bootstrap-select': '../libs/bootstrap-select/dist/js/bootstrap-select.min',
'bootstrap-table': '../libs/bootstrap-table/dist/bootstrap-table.min',
'bootstrap-table-export': '../libs/bootstrap-table/dist/extensions/export/bootstrap-table-export.min',
'bootstrap-table-mobile': '../libs/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile',
'bootstrap-table-advancedsearch': 'bootstrap-table-advancedsearch',
'bootstrap-table-lang': '../libs/bootstrap-table/dist/locale/bootstrap-table-zh-CN',
'typeahead': '../libs/typeahead.js/dist/typeahead.jquery.min',
'bloodhound': '../libs/typeahead.js/dist/bloodhound.min',
'tableexport': '../libs/tableExport.jquery.plugin/tableExport.min',
'dropzone': '../libs/dropzone/dist/min/dropzone-amd-module.min',
'less': '../libs/less/dist/less.min',
'dragsort': '../libs/dragsort/jquery.dragsort',
'sortable': '../libs/Sortable/Sortable.min',
'addtabs': '../libs/jquery-addtabs/jquery.addtabs',
'slimscroll': '../libs/jquery-slimscroll/jquery.slimscroll',
'crontab': '../libs/jqcron/src/jqCron.cn',
'summernote': '../libs/summernote/dist/lang/summernote-zh-CN.min',
'validator': '../libs/nice-validator/dist/local/zh-CN',
'plupload': '../libs/plupload/js/plupload.min',
'toastr': '../libs/toastr/toastr',
'jstree': '../libs/jstree/dist/jstree.min',
'layer': '../libs/layer/src/layer',
'echarts': '../libs/echarts/dist/echarts.min',
'cookie': '../libs/jquery.cookie/jquery.cookie',
'template': '../libs/art-template/dist/template-native',
},
// shim依赖配置
shim: {
'bootstrap': ['jquery'],
'bootstrap-table': {
deps: ['bootstrap', 'css!../libs/bootstrap-table/dist/bootstrap-table.min.css'],
exports: '$.fn.bootstrapTable'
},
'bootstrap-table-lang': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-export': {
deps: ['bootstrap-table', 'tableexport'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-mobile': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'bootstrap-table-advancedsearch': {
deps: ['bootstrap-table'],
exports: '$.fn.bootstrapTable.defaults'
},
'tableexport': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'slimscroll': {
deps: ['jquery'],
exports: '$.fn.extend'
},
'adminlte': {
deps: ['bootstrap', 'slimscroll'],
exports: '$.AdminLTE'
},
'typeahead': {
deps: ['jquery'],
init: function ($) {
return require.s.contexts._.registry['typeahead.js'].factory($);
}
},
'crontab': ['../libs/jqcron/src/jqCron', 'css!../libs/jqcron/src/jqCron.css'],
'bootstrap-checkbox': ['jquery'],
'bootstrap-radio': ['jquery'],
'bootstrap-switch': ['jquery'],
'bootstrap-dialog': ['css!../libs/bootstrap3-dialog/dist/css/bootstrap-dialog.min.css'],
'bootstrap-datetimepicker': [
'css!../libs/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.min.css',
'moment/locale/zh-cn'
],
'bootstrap-tagsinput': [
'css!../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput-typeahead.css',
'css!../libs/bootstrap-tagsinput/dist/bootstrap-tagsinput.css',
'jquery',
'typeahead'
],
'bootstrap-select': ['css!../libs/bootstrap-select/dist/css/bootstrap-select.min.css', ],
'summernote': ['../libs/summernote/dist/summernote.min', 'css!../libs/summernote/dist/summernote.css'],
// 'toastr': ['css!../libs/toastr/toastr.min.css'],
'jstree': ['css!../libs/jstree/dist/themes/default/style.css', ],
'plupload': {
deps: [
'../libs/plupload/js/moxie.min'
],
exports: "plupload"
},
// 'layer': ['css!../libs/layer/build/skin/default/layer.css'],
validator: {
deps: ['../libs/nice-validator/dist/jquery.validator', 'css!../libs/nice-validator/dist/jquery.validator.css']
}
},
map: {
'*': {
'css': '../libs/require-css/css.min'
}
},
charset: 'utf-8' // 文件编码
});
\ No newline at end of file
#! /bin/bash
node r.js -o build-frontend.js
node r.js -o build-frontend-css.js
node r.js -o build-backend.js
node r.js -o build-backend-css.js
echo "done"
... ... @@ -5,7 +5,10 @@ require.config({
location: '../libs/moment',
main: 'moment'
}],
//在打包压缩时将会把include中的模块合并到主文件中
include: ['css', 'layer', 'toastr', 'backend', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs'],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
... ...
... ... @@ -22,7 +22,10 @@ require.config({
location: '../libs/moment',
main: 'moment'
}],
//在打包压缩时将会把include中的模块合并到主文件中
include: ['css', 'layer', 'toastr', 'backend', 'table', 'form', 'dragsort', 'drag', 'drop', 'addtabs'],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
... ...
... ... @@ -5,7 +5,10 @@ require.config({
location: '../libs/moment',
main: 'moment'
}],
//在打包压缩时将会把include中的模块合并到主文件中
include: ['css', 'layer', 'toastr', 'frontend'],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
... ...
... ... @@ -22,7 +22,10 @@ require.config({
location: '../libs/moment',
main: 'moment'
}],
//在打包压缩时将会把include中的模块合并到主文件中
include: ['css', 'layer', 'toastr', 'frontend'],
paths: {
'lang': "empty:",
'config': 'require-config',
'bootstrap-checkbox': 'bootstrap-checkbox',
'bootstrap-radio': 'bootstrap-radio',
... ...