minify
In this article you’ll learn how to use Laravel’s Artisan command line tool, and how to create a customized command. Note that you need to be familiar with the Laravel framework to get the most of this article.
在本文中,您将学习如何使用Laravel的Artisan命令行工具,以及如何创建自定义命令。 请注意,您需要熟悉Laravel框架才能充分利用本文。
我们在建什么 (What are we building)
In this tutorial we’re going to build a command to minify our css assets, which will be used like this:
在本教程中,我们将构建一个命令来最小化我们的css资产,它将像这样使用:
cssmin 'output_path' 'file1'...'fileN' --comments --concat
output_path
: (required) path to save the minified files, (style.css
->style.min.css
).output_path
:(必需)保存缩小文件的路径(style.css
>style.min.css
)。file1 ... fileN
: (required) list of files to minify.file1 ... fileN
:(必需)要缩小的文件列表。--comments
: (optional) add this option to keep comments.--comments
:(可选)添加此选项以保留注释。--concat
: (optional) concatenate the minified files into one file calledall.min.css
.--concat
:(可选)将缩小的文件连接到一个名为all.min.css
文件中。
什么是Laravel命令 (What is a Laravel Command)
Artisan
is the name of the command line utility in Laravel. It comes with a set of predefined commands, which you can list with php artisan list
. If you want to show the help for a specific command, you can use php artisan help command
.
Artisan
是Laravel中命令行实用程序的名称。 它带有一组预定义的命令,您可以使用php artisan list
这些命令。 如果要显示特定命令的帮助,可以使用php artisan help command
。
创建CSS Minifier命令 (Creating the Css Minifier Command)
To create an artisan command, you can use the command:make
command. This command accepts one argument:
要创建一个工匠命令,可以使用command:make
命令。 此命令接受一个参数:
name
: the class name for the command.name
:命令的类名。
and three options:
和三个选项:
--command
: the name that should be typed to run the command.--command
:应键入以运行命令的名称。--path
: by default the commands are stored within theapp/commands
folder, however, you can change that with this option.--path
:默认情况下,命令存储在app/commands
文件夹中,但是,您可以使用此选项进行更改。--namespace
: you can use this option to namespace your set of commands, e.g. in the commandcommand:make
, themake
command is under thecommand
namespace.--namespace
:您可以使用此选项对命令集进行命名空间,例如在命令command:make
,make
命令位于command
命名空间下。
Now, to create our command we will use php artisan command:make CssMinCommand --command=cssmin
which will create a CssMinCommand.php
file within our app/commands
directory.
现在,要创建命令,我们将使用php artisan command:make CssMinCommand --command=cssmin
,它将在我们的app/commands
目录中创建一个CssMinCommand.php
文件。
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
class CssminCommand extends Command{
protected $name = 'cssmin';
protected $description = 'Command description.';
public function __construct(){
parent::__construct();
}
public function fire(){
//
}
protected function getArguments(){
return array(
array('example', InputArgument::REQUIRED, 'An example argument.'),
);
}
protected function getOptions(){
return array(
array('example', null, InputOption::VALUE_OPTIONAL, 'An example option.', null),
);
}
}
Our CssMinCommand
class extends the Illuminate\Console\Command
and overrides two methods ( getArguments
, getOptions
).
我们的CssMinCommand
类扩展了Illuminate\Console\Command
并覆盖了两个方法( getArguments
, getOptions
)。
getArguments
: this function returns an array of arguments that should be passed to the command, (ex: the list of files that we pass to thecssmin
command).getArguments
:此函数返回应传递给命令的参数数组(例如:我们传递给cssmin
命令的文件列表)。getOptions
: returns a list of options or switches that you may pass to the command. (e.g.--comments
).getOptions
:返回您可以传递给命令的选项或开关的列表。 (例如--comments
)。
Note: options may or may not have values, --comments
is only a flag that returns true
if it’s passed to the command, whereas --ouptput='public/assets'
will return a value.
注意:选项可能有也可能没有值,-- --comments
只是将其传递给命令时返回true
的标志,而--ouptput='public/assets'
将返回一个值。
When your command is executed, the fire
method is called, so this is where we need to put our command logic.
当您执行命令时,将调用fire
方法,因此这是我们需要放置命令逻辑的地方。
注册命令 (Registering the Command)
if you try to run our command php artisan cssmin 'args'
you’ll get a Command "cssmin" is not defined
.
如果您尝试运行我们的命令php artisan cssmin 'args'
,则会得到Command "cssmin" is not defined
的Command "cssmin" is not defined
。
To register a command you need to add it to the artisan.php
file:
要注册命令,您需要将其添加到artisan.php
文件中:
Artisan::add( new CssMinCommand );
//or through the container
Artisan::add( App::make("CssMinCommand") );
If you don’t want to put your commands in the artisan.php
file, you can create a separate file and include it, or if you’re creating a package you can register them in your Service Provider.
如果您不想将命令放在artisan.php
文件中,则可以创建一个单独的文件并将其包含在其中,或者如果要创建软件包,则可以在Service Provider中注册它们。
争论 (Arguments)
In our getArguments
method we will define our output
and files
. To define an argument, we need to pass an array of values:
在我们的getArguments
方法中,我们将定义我们的output
和files
。 要定义一个参数,我们需要传递一个值数组:
array( 'name', 'mode', 'description', 'defaultValue' )
name
: key name to be used when retrieving arguments.name
:检索参数时要使用的键名。mode
: can have one of the three options:mode
:可以具有以下三个选项之一:InputArgument::REQUIRED
: argument is required.InputArgument::REQUIRED
:参数是必需的。InputArgument::OPTIONAL
: argument is optional.InputArgument::OPTIONAL
:参数是可选的。InputArgument::IS_ARRAY
: argument accepts multiple values ( ex:file1...fileN
).InputArgument::IS_ARRAY
:参数接受多个值(例如:file1...fileN
)。
However, you can combine them like
InputArgument::IS_ARRAY | InputArgument::REQUIRED
(argument is required and must be an array).但是,您可以像
InputArgument::IS_ARRAY | InputArgument::REQUIRED
一样组合它们InputArgument::IS_ARRAY | InputArgument::REQUIRED
InputArgument::IS_ARRAY | InputArgument::REQUIRED
(参数是必需的,必须为数组)。description
: useful when printing the command help.description
:在打印命令帮助时很有用。defaultValue
: if argument was not provided.defaultValue
:如果未提供参数。
So our getArguments
method will be:
因此,我们的getArguments
方法将是:
protected function getArguments(){
return array(
array(
'output',
InputArgument::REQUIRED,
'Path to output directory'
),
array(
'files',
InputArgument::IS_ARRAY | InputArgument::OPTIONAL ,
"List of css files to minify"
),
);
}
Note: when using the IS_ARRAY
argument it should be the last one on the returned arguments array. (obviously).
注意:使用IS_ARRAY
参数时,它应该是返回的参数数组中的最后一个。 (明显)。
选件 (Options)
Our cssmin
command will only have two options. To define an option we pass an array:
我们的cssmin
命令将只有两个选项。 要定义一个选项,我们传递一个数组:
array('name', 'shortcut', 'mode', 'description', 'defaultValue')
name
: the name of your option (ex:comments
).name
:您的选项的名称(例如comments
)。shortcut
: a shorter version of your option (ex:--verbose
and-v
).shortcut
:您选择的简短版本(例如:----verbose
和-v
)。mode
: can be one of the four options (InputOption::VALUE_IS_ARRAY
,InputOption::VALUE_OPTIONAL
,InputOption::VALUE_REQUIRED
,InputOption::VALUE_NONE
), the first three values are similar to the arguments.mode
:可以是四个选项之一(InputOption::VALUE_IS_ARRAY
,InputOption::VALUE_OPTIONAL
,InputOption::VALUE_REQUIRED
,InputOption::VALUE_NONE
),前三个值与参数类似。VALUE_NONE
: indicates that the option is a boolean flag ( ex:--verbose
).VALUE_NONE
:指示该选项是一个布尔标志(例如:----verbose
)。
description
: useful when printing the command help.description
:在打印命令帮助时很有用。defaultValue
: if option value was not provided.defaultValue
:如果未提供选项值。
So our getOptions
method will be:
因此,我们的getOptions
方法将是:
protected function getOptions(){
return array(
array('comments', 'c', InputOption::VALUE_NONE, 'Don\'t strip comments' , null),
array('concat', null, InputOption::VALUE_NONE, 'Concat the minified result to one file' , null),
);
}
运行命令 (Running the Command)
When our fire
method is called we need to gather our arguments and options. We can make a separate function to do that for us:
调用fire
方法时,我们需要收集参数和选项。 我们可以为它做一个单独的功能:
private function init(){
// retrun an array
$this->files = $this->argument('files');
// return a string
$this->output_path = $this->argument('output');
// return true if passed, otherwise false
$this->comments = $this->option('comments');
// return true if passed, otherwise false
$this->concat = $this->option('concat');
}
The argument
and option
methods take a key as an argument and return the appropriate value.
argument
和option
方法将键作为参数并返回适当的值。
To keep our example clean and simple we will use this simple function with a small modification for the minification process.
为了使示例简洁明了,我们将在缩小过程中使用此简单功能并进行少量修改。
private function minify( $css, $comments ){
// Normalize whitespace
$css = preg_replace( '/\s+/', ' ', $css );
// Remove comment blocks, everything between /* and */, unless preserved with /*! ... */
if( !$comments ){
$css = preg_replace( '/\/\*[^\!](.*?)\*\//', '', $css );
}//if
// Remove ; before }
$css = preg_replace( '/;(?=\s*})/', '', $css );
// Remove space after , : ; { } */ >
$css = preg_replace( '/(,|:|;|\{|}|\*\/|>) /', '$1', $css );
// Remove space before , ; { } ( ) >
$css = preg_replace( '/ (,|;|\{|}|\(|\)|>)/', '$1', $css );
// Strips leading 0 on decimal values (converts 0.5px into .5px)
$css = preg_replace( '/(:| )0\.([0-9]+)(%|em|ex|px|in|cm|mm|pt|pc)/i', '${1}.${2}${3}', $css );
// Strips units if value is 0 (converts 0px to 0)
$css = preg_replace( '/(:| )(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/i', '${1}0', $css );
// Converts all zeros value into short-hand
$css = preg_replace( '/0 0 0 0/', '0', $css );
// Shortern 6-character hex color codes to 3-character where possible
$css = preg_replace( '/#([a-f0-9])\\1([a-f0-9])\\2([a-f0-9])\\3/i', '#\1\2\3', $css );
return trim( $css );
}//minify
Now to process our arguments (files) we’re going to make a separate method to do the job.
现在要处理参数(文件),我们将制作一个单独的方法来完成这项工作。
private function processFiles(){
// array of minified css
$css_result = [];
foreach ( $this->files as $file ) {
//read file content
$file_content = file_get_contents( $file );
//minify CSS and add it to the result array
$css_result[] = $this->minify( $file_content, $this->comments );
}//foreach
// if the concat flag is true
if( $this->concat ){
// join the array of minified css
$css_concat = implode( PHP_EOL, $css_result );
// save to file
file_put_contents($this->output_path . '/all.min.css', $css_concat);
}//if
else{
foreach ($css_result as $key => $css) {
//remove '.css' to add '.min.css'
$filename = basename( $this->files[$key], '.css' ) . '.min.css';
// save to file
file_put_contents($this->output_path . '/' . $filename, $css);
}//for
}//else
}//processFiles
Finally, our fire
method will only call the two methods:
最后,我们的fire
方法将仅调用以下两个方法:
public function fire(){
$this->init();
$this->processFiles();
}
Tip: You can also run an external command using the call
method.
提示:您还可以使用call
方法运行外部命令。
$this->call('command:name', array('argument' => 'foo', '--option' => 'bar'));
To test our command, we’re going to copy some css files into our public/css
directory, and then run the command.
为了测试我们的命令,我们将一些css文件复制到我们的public/css
目录中,然后运行该命令。
php artisan cssmin 'public/css' 'public/css/style.css' 'public/css/responsive.css'
php artisan cssmin 'public/css' 'public/css/style.css' 'public/css/responsive.css' --comments --concat
The first command will create two files (style.min.css
, responsive.min.css
) on the public/css
directory.
第一个命令将创建两个文件( style.min.css
, responsive.min.css
的) public/css
目录。
Because we used the --comments
and --concat
flags, we’re going to get a file called all.min.css
containing the two files with comments left.
因为我们使用了--comments
和--concat
标志,所以我们将获得一个名为all.min.css
的文件,其中包含两个带有注释的文件。
Our command is not very descriptive and doesn’t give any messages or notifications!
我们的命令描述性不是很好,并且不会给出任何消息或通知!
改善命令 (Improving the Command)
Before we continue, on the final GitHub repository I will create a new tag for our command so you can switch and test each one.
在继续之前,我将在最终的GitHub存储库上为命令创建一个新标签,以便您可以切换和测试每个标签。
To make the command a little verbose, Laravel provides us with some output functions:
为了使命令稍微冗长一些,Laravel为我们提供了一些输出函数:
$this->line("This is a simple line message");
$this->info("This is an info");
$this->comment("This is a comment");
$this->question("This is a question");
$this->error("This is an error");
This will output:
这将输出:
![title Output](https://uploads.sitepoint.com/wp-content/uploads/2014/06/1402500043log_messages.png)
Beside just displaying messages, you can ask the user for information, ex:
除了显示消息外,您还可以要求用户提供信息,例如:
$confirm = $this->confirm("'style.min.css' already exists, overwrite?", false);
$filename = $this->ask("Save the file as?", 'all.min.css');
$choice = $this->choice(
'Please select a level of minication:',
[ 'minify all', 'leave comments' ],
'default value'
);
$password = $this->secret('Type your password to confirm:');
The
confirm
method takes two arguments, a question message and a default value if the user type something different thany/n
.如果用户键入的内容不同于
y/n
,则confirm
方法采用两个参数,即问题消息和默认值。The
ask
method will ask the user for an input instead of justy/n
, and if it’s left empty, the default value is returned.ask
方法将要求用户输入而不是y/n
,如果为空,则返回默认值。The
choice
method will give the user a numbered list to choose from, and if it’s left empty, the default value is returned.choice
方法将为用户提供一个编号列表供您选择,如果保留为空,则返回默认值。The
secret
method will prompt the user with a question and hide the typing, but the user input will be returned.secret
方法将提示用户一个问题并隐藏其键入内容,但将返回用户输入。
In fact, Laravel is just making Symfony’s Console API simpler and more verbose, and there is so much more if you want dig in.
实际上,Laravel只是使Symfony的Console API更简单,更冗长,如果您想深入了解的话,还有更多的东西。
Let’s make our command more verbose and keep the user updated about the performed tasks.
让我们使命令更详细,并使用户了解所执行任务的最新情况。
private function processFiles(){
$css_result = [];
foreach ( $this->files as $file ) {
$this->comment("'{$file}'");
$this->info("Loading file");
//read file content
$file_content = file_get_contents( $file );
$this->info("minifying");
//minify CSS and add it to the result array
$css_result[] = $this->minify( $file_content, $this->comments );
}//foreach
if( $this->concat ){
$this->comment("Concatenating into one file");
$css_concat = implode( PHP_EOL, $css_result );
$this->info("Saving to '{$this->output_path}/all.min.css'");
file_put_contents($this->output_path . '/all.min.css', $css_concat);
}//if
else{
foreach ($css_result as $key => $css) {
//remove '.css' to add '.min.css'
$filename = basename( $this->files[$key], '.css' ) . '.min.css';
$this->comment("Saving '{$filename}'");
file_put_contents($this->output_path . '/' . $filename, $css);
}//for
}//else
}//processFiles
Our function now prints some useful messages to keep track of what’s going on.
现在,我们的功能会打印一些有用的消息,以跟踪发生的情况。
![title command log](https://i-blog.csdnimg.cn/blog_migrate/b78128a70d8abe2d65cba309e68c7457.webp?x-image-process=image/format,png)
Note: This will be tagged as v2
of our command on the GitHub repository.
注意:这将在GitHub存储库上标记为我们命令的v2
。
When creating an application, we are used to dumping the list of available routes (php artisan routes
).
创建应用程序时,我们习惯于转储可用路由列表( php artisan routes
)。
![title routes](https://uploads.sitepoint.com/wp-content/uploads/2014/06/1402500045routes.png)
Symfony provides a function that lets you print a such table easily. Check the documentation for an example. We’ll see next how we can use some Symfony Console Helpers.
Symfony提供了使您可以轻松打印此类表格的功能。 查看文档中的示例。 接下来,我们将看到如何使用一些Symfony控制台助手。
使用Symfony控制台助手 (Using the Symfony Console Helpers)
To illustrate the use of some Symfony Helpers we will use the Progress Helper to keep the user updated about the job progress.
为了说明某些Symfony Helper的用法,我们将使用Progress Helper使用户保持有关工作进度的最新信息。
At the end of our init
method we will require a progress from the HelperSet
, then start our progress bar.
在init
方法的最后,我们将需要HelperSet
的进度,然后启动进度栏。
$this->progressbar = $this->getHelperSet()->get('progress');
$this->progressbar->start($this->output, count($this->files) );
The start
method accepts two arguments, $this->output
is a ConsoleOuput
instance from the Symfony Console. The second argument is the maximum number of steps.
start
方法接受两个参数, $this->output
是Symfony Console中的ConsoleOuput
实例。 第二个参数是最大步数。
Every time we process a file in our processFiles
method we will advance the progress bar by one step, and when the job is done we will end the progress bar and print a notification message.
每次我们在processFiles
方法中处理文件时,我们都会将进度条前进一步,完成工作后,我们将结束进度条并打印一条通知消息。
private function processFiles(){
$css_result = [];
foreach ( $this->files as $file ) {
//read file content
$file_content = file_get_contents( $file );
//minify CSS and add it to the result array
$css_result[] = $this->minify( $file_content, $this->comments );
// sleep for one second to see the effect
//sleep(1);
$this->progressbar->advance();
}//foreach
if( $this->concat ){
$css_concat = implode( PHP_EOL, $css_result );
file_put_contents($this->output_path . '/all.min.css', $css_concat);
}//if
else{
foreach ($css_result as $key => $css) {
//remove '.css' to add '.min.css'
$filename = basename( $this->files[$key], '.css' ) . '.min.css';
file_put_contents($this->output_path . '/' . $filename, $css);
}//for
}//else
$this->progressbar->finish();
$this->info('Done');
}//processFiles
You can try the command with multiple files or uncomment the sleep
function line to see a live effect.
您可以尝试对多个文件使用该命令,或者取消注释sleep
功能行以查看实时效果。
![title progressbar](https://i-blog.csdnimg.cn/blog_migrate/36d946dc2656a966dc3204ac2429e78c.webp?x-image-process=image/format,png)
Note: This version will be tagged as v3
on the final repository.
注意:此版本将在最终存储库中标记为v3
。
结论 (Conclusion)
In this article we’ve learned how create and extend Laravel commands. Laravel has a lot of built-in commands that you can explore, and you can also check our final repository on GitHub to test the final result. Questions? Comments? Would you like to see more Artisan Command tutorials? Let us know!
在本文中,我们学习了如何创建和扩展Laravel命令。 Laravel有很多内置命令可供您探索,您还可以在GitHub上查看我们的最终存储库以测试最终结果。 有什么问题吗 注释? 您想查看更多Artisan Command教程吗? 让我们知道!
翻译自: https://www.sitepoint.com/create-laravel-css-minify-command/
minify