diff --git a/apps/advanced/backend/config/AppAsset.php b/apps/advanced/backend/config/AppAsset.php
new file mode 100644
index 0000000..525b693
--- /dev/null
+++ b/apps/advanced/backend/config/AppAsset.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace backend\config;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+	public $basePath = '@wwwroot';
+	public $baseUrl = '@www';
+	public $css = array(
+		'css/site.css',
+	);
+	public $js = array(
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+		'yii\bootstrap\ResponsiveAsset',
+	);
+}
diff --git a/apps/advanced/backend/config/assets.php b/apps/advanced/backend/config/assets.php
deleted file mode 100644
index ee0d610..0000000
--- a/apps/advanced/backend/config/assets.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-return array(
-	'app' => array(
-		'basePath' => '@wwwroot',
-		'baseUrl' => '@www',
-		'css' => array(
-			'css/site.css',
-		),
-		'js' => array(
-
-		),
-		'depends' => array(
-			'yii',
-			'yii/bootstrap/responsive',
-		),
-	),
-);
diff --git a/apps/advanced/backend/config/main.php b/apps/advanced/backend/config/main.php
index 88838b9..377d34c 100644
--- a/apps/advanced/backend/config/main.php
+++ b/apps/advanced/backend/config/main.php
@@ -23,9 +23,6 @@ return array(
 			'class' => 'yii\web\User',
 			'identityClass' => 'common\models\User',
 		),
-		'assetManager' => array(
-			'bundles' => require(__DIR__ . '/assets.php'),
-		),
 		'log' => array(
 			'targets' => array(
 				array(
diff --git a/apps/advanced/backend/views/layouts/main.php b/apps/advanced/backend/views/layouts/main.php
index cf21f9d..84ad1ad 100644
--- a/apps/advanced/backend/views/layouts/main.php
+++ b/apps/advanced/backend/views/layouts/main.php
@@ -1,4 +1,5 @@
 <?php
+use backend\config\AppAsset;
 use yii\helpers\Html;
 use yii\widgets\Menu;
 use yii\widgets\Breadcrumbs;
@@ -7,7 +8,7 @@ use yii\widgets\Breadcrumbs;
  * @var $this \yii\base\View
  * @var $content string
  */
-$this->registerAssetBundle('app');
+AppAsset::register($this);
 ?>
 <?php $this->beginPage(); ?>
 <!DOCTYPE html>
diff --git a/apps/advanced/frontend/config/AppAsset.php b/apps/advanced/frontend/config/AppAsset.php
new file mode 100644
index 0000000..0a3a5e8
--- /dev/null
+++ b/apps/advanced/frontend/config/AppAsset.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace frontend\config;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+	public $basePath = '@wwwroot';
+	public $baseUrl = '@www';
+	public $css = array(
+		'css/site.css',
+	);
+	public $js = array(
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+		'yii\bootstrap\ResponsiveAsset',
+	);
+}
diff --git a/apps/advanced/frontend/config/assets.php b/apps/advanced/frontend/config/assets.php
deleted file mode 100644
index ee0d610..0000000
--- a/apps/advanced/frontend/config/assets.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-return array(
-	'app' => array(
-		'basePath' => '@wwwroot',
-		'baseUrl' => '@www',
-		'css' => array(
-			'css/site.css',
-		),
-		'js' => array(
-
-		),
-		'depends' => array(
-			'yii',
-			'yii/bootstrap/responsive',
-		),
-	),
-);
diff --git a/apps/advanced/frontend/config/main.php b/apps/advanced/frontend/config/main.php
index 5be2849..9051506 100644
--- a/apps/advanced/frontend/config/main.php
+++ b/apps/advanced/frontend/config/main.php
@@ -22,9 +22,6 @@ return array(
 			'class' => 'yii\web\User',
 			'identityClass' => 'common\models\User',
 		),
-		'assetManager' => array(
-			'bundles' => require(__DIR__ . '/assets.php'),
-		),
 		'log' => array(
 			'traceLevel' => YII_DEBUG ? 3 : 0,
 			'targets' => array(
diff --git a/apps/advanced/frontend/views/layouts/main.php b/apps/advanced/frontend/views/layouts/main.php
index 0af2fe2..8903779 100644
--- a/apps/advanced/frontend/views/layouts/main.php
+++ b/apps/advanced/frontend/views/layouts/main.php
@@ -1,4 +1,5 @@
 <?php
+use frontend\config\AppAsset;
 use yii\helpers\Html;
 use yii\widgets\Menu;
 use yii\widgets\Breadcrumbs;
@@ -7,7 +8,7 @@ use yii\widgets\Breadcrumbs;
  * @var $this \yii\base\View
  * @var $content string
  */
-$this->registerAssetBundle('app');
+AppAsset::register($this);
 ?>
 <?php $this->beginPage(); ?>
 <!DOCTYPE html>
diff --git a/apps/basic/assets/.gitkeep b/apps/basic/assets/.gitkeep
deleted file mode 100644
index 72e8ffc..0000000
--- a/apps/basic/assets/.gitkeep
+++ /dev/null
@@ -1 +0,0 @@
-*
diff --git a/apps/basic/config/AppAsset.php b/apps/basic/config/AppAsset.php
new file mode 100644
index 0000000..2546969
--- /dev/null
+++ b/apps/basic/config/AppAsset.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace app\config;
+
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AppAsset extends AssetBundle
+{
+	public $basePath = '@wwwroot';
+	public $baseUrl = '@www';
+	public $css = array(
+		'css/site.css',
+	);
+	public $js = array(
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+		'yii\bootstrap\ResponsiveAsset',
+	);
+}
diff --git a/apps/basic/config/assets.php b/apps/basic/config/assets.php
deleted file mode 100644
index ee0d610..0000000
--- a/apps/basic/config/assets.php
+++ /dev/null
@@ -1,18 +0,0 @@
-<?php
-
-return array(
-	'app' => array(
-		'basePath' => '@wwwroot',
-		'baseUrl' => '@www',
-		'css' => array(
-			'css/site.css',
-		),
-		'js' => array(
-
-		),
-		'depends' => array(
-			'yii',
-			'yii/bootstrap/responsive',
-		),
-	),
-);
diff --git a/apps/basic/config/web.php b/apps/basic/config/web.php
index 10e8856..d576599 100644
--- a/apps/basic/config/web.php
+++ b/apps/basic/config/web.php
@@ -18,9 +18,6 @@ return array(
 			'class' => 'yii\web\User',
 			'identityClass' => 'app\models\User',
 		),
-		'assetManager' => array(
-			'bundles' => require(__DIR__ . '/assets.php'),
-		),
 		'log' => array(
 			'traceLevel' => YII_DEBUG ? 3 : 0,
 			'targets' => array(
diff --git a/apps/basic/views/layouts/main.php b/apps/basic/views/layouts/main.php
index 77f7b8d..726ad41 100644
--- a/apps/basic/views/layouts/main.php
+++ b/apps/basic/views/layouts/main.php
@@ -7,7 +7,7 @@ use yii\widgets\Breadcrumbs;
  * @var $this \yii\base\View
  * @var $content string
  */
-$this->registerAssetBundle('app');
+app\config\AppAsset::register($this);
 ?>
 <?php $this->beginPage(); ?>
 <!DOCTYPE html>
diff --git a/docs/guide/upgrade-from-v1.md b/docs/guide/upgrade-from-v1.md
index c3cbf31..79c6c3f 100644
--- a/docs/guide/upgrade-from-v1.md
+++ b/docs/guide/upgrade-from-v1.md
@@ -311,9 +311,10 @@ Yii 2.0 introduces a new concept called *asset bundle*. It is similar to script
 packages (managed by `CClientScript`) in 1.1, but with better support.
 
 An asset bundle is a collection of asset files (e.g. JavaScript files, CSS files, image files, etc.)
-under a directory. By registering an asset bundle via `View::registerAssetBundle()`, you
-will be able to make the assets in that bundle accessible via Web, and the current page
-will automatically contain references to the JavaScript and CSS files in that bundle.
+under a directory. Each asset bundle is represented as a class extending `AssetBundle`.
+By registering an asset bundle via `AssetBundle::register()`, you will be able to make
+the assets in that bundle accessible via Web, and the current page will automatically
+contain the references to the JavaScript and CSS files specified in that bundle.
 
 
 
diff --git a/extensions/jui/yii/jui/CoreAsset.php b/extensions/jui/yii/jui/CoreAsset.php
new file mode 100644
index 0000000..e757ea7
--- /dev/null
+++ b/extensions/jui/yii/jui/CoreAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\jui;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class CoreAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/jui/assets';
+	public $js = array(
+		'jquery.ui.core.js',
+	);
+	public $depends = array(
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/extensions/jui/yii/jui/WidgetAsset.php b/extensions/jui/yii/jui/WidgetAsset.php
new file mode 100644
index 0000000..fde1630
--- /dev/null
+++ b/extensions/jui/yii/jui/WidgetAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\jui;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class WidgetAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/jui/assets';
+	public $js = array(
+		'jquery.ui.widget.js',
+	);
+	public $depends = array(
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/extensions/jui/yii/jui/assets.php b/extensions/jui/yii/jui/assets.php
index d2d8f7c..707cadc 100644
--- a/extensions/jui/yii/jui/assets.php
+++ b/extensions/jui/yii/jui/assets.php
@@ -1,20 +1,8 @@
 <?php
 
 return array(
-	'yii/jui/core' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'jquery.ui.core.js',
-		),
-		'depends' => array('yii/jquery'),
-	),
-	'yii/jui/widget' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'jquery.ui.widget.js',
-		),
-		'depends' => array('yii/jquery'),
-	),
+	yii\jui\CoreAsset::className(),
+	yii\jui\WidgetAsset::className(),
 	'yii/jui/accordion' => array(
 		'sourcePath' => __DIR__ . '/assets',
 		'js' => array(
diff --git a/framework/yii/YiiBase.php b/framework/yii/YiiBase.php
index 23e8f05..25573b7 100644
--- a/framework/yii/YiiBase.php
+++ b/framework/yii/YiiBase.php
@@ -69,7 +69,7 @@ class YiiBase
 	 * @see getAlias
 	 * @see setAlias
 	 */
-	public static $aliases;
+	public static $aliases = array('@yii' => __DIR__);
 	/**
 	 * @var array initial property values that will be applied to objects newly created via [[createObject]].
 	 * The array keys are class names without leading backslashes "\", and the array values are the corresponding
@@ -616,10 +616,3 @@ class YiiBase
 		return get_object_vars($object);
 	}
 }
-
-YiiBase::$aliases = array(
-	'@yii' => array(
-		'@yii/bootstrap' => __DIR__ . '/bootstrap',
-		'@yii' => __DIR__,
-	),
-);
diff --git a/framework/yii/assets.php b/framework/yii/assets.php
index fd3c731..dd657f3 100644
--- a/framework/yii/assets.php
+++ b/framework/yii/assets.php
@@ -1,61 +1,11 @@
 <?php
 
 return array(
-	'yii' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'yii.js',
-		),
-		'depends' => array('yii/jquery'),
-	),
-	'yii/jquery' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			YII_DEBUG ? 'jquery.js' : 'jquery.min.js',
-		),
-	),
-	'yii/validation' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'yii.validation.js',
-		),
-		'depends' => array('yii'),
-	),
-	'yii/form' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'yii.activeForm.js',
-		),
-		'depends' => array('yii'),
-	),
-	'yii/captcha' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'yii.captcha.js',
-		),
-		'depends' => array('yii'),
-	),
-	'yii/punycode' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			YII_DEBUG ? 'punycode/punycode.js' : 'punycode/punycode.min.js',
-		),
-	),
-	'yii/maskedinput' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'jquery.maskedinput.js',
-		),
-		'depends' => array('yii/jquery'),
-	),
-	'yii/debug' => array(
-		'sourcePath' => __DIR__ . '/debug/assets',
-		'css' => array(
-			'main.css',
-		),
-		'depends' => array(
-			'yii',
-			'yii/bootstrap/responsive',
-		),
-	),
+	yii\web\YiiAsset::className(),
+	yii\web\JqueryAsset::className(),
+	yii\validators\PunycodeAsset::className(),
+	yii\validators\ValidationAsset::className(),
+	yii\widgets\ActiveFormAsset::className(),
+	yii\widgets\CaptchaAsset::className(),
+	yii\widgets\MaskedInputAsset::className(),
 );
diff --git a/framework/yii/base/View.php b/framework/yii/base/View.php
index d49c69c..2d37efc 100644
--- a/framework/yii/base/View.php
+++ b/framework/yii/base/View.php
@@ -10,6 +10,8 @@ namespace yii\base;
 use Yii;
 use yii\helpers\FileHelper;
 use yii\helpers\Html;
+use yii\web\JqueryAsset;
+use yii\web\AssetBundle;
 use yii\widgets\Block;
 use yii\widgets\ContentDecorator;
 use yii\widgets\FragmentCache;
@@ -72,15 +74,15 @@ class View extends Component
 	/**
 	 * This is internally used as the placeholder for receiving the content registered for the head section.
 	 */
-	const PL_HEAD = '<![CDATA[YII-BLOCK-HEAD]]>';
+	const PH_HEAD = '<![CDATA[YII-BLOCK-HEAD]]>';
 	/**
 	 * This is internally used as the placeholder for receiving the content registered for the beginning of the body section.
 	 */
-	const PL_BODY_BEGIN = '<![CDATA[YII-BLOCK-BODY-BEGIN]]>';
+	const PH_BODY_BEGIN = '<![CDATA[YII-BLOCK-BODY-BEGIN]]>';
 	/**
 	 * This is internally used as the placeholder for receiving the content registered for the end of the body section.
 	 */
-	const PL_BODY_END = '<![CDATA[YII-BLOCK-BODY-END]]>';
+	const PH_BODY_END = '<![CDATA[YII-BLOCK-BODY-END]]>';
 
 
 	/**
@@ -519,9 +521,9 @@ class View extends Component
 
 		$content = ob_get_clean();
 		echo strtr($content, array(
-			self::PL_HEAD => $this->renderHeadHtml(),
-			self::PL_BODY_BEGIN => $this->renderBodyBeginHtml(),
-			self::PL_BODY_END => $this->renderBodyEndHtml(),
+			self::PH_HEAD => $this->renderHeadHtml(),
+			self::PH_BODY_BEGIN => $this->renderBodyBeginHtml(),
+			self::PH_BODY_END => $this->renderBodyEndHtml(),
 		));
 
 		unset(
@@ -540,7 +542,7 @@ class View extends Component
 	 */
 	public function beginBody()
 	{
-		echo self::PL_BODY_BEGIN;
+		echo self::PH_BODY_BEGIN;
 		$this->trigger(self::EVENT_BEGIN_BODY);
 	}
 
@@ -550,7 +552,7 @@ class View extends Component
 	public function endBody()
 	{
 		$this->trigger(self::EVENT_END_BODY);
-		echo self::PL_BODY_END;
+		echo self::PH_BODY_END;
 	}
 
 	/**
@@ -558,13 +560,14 @@ class View extends Component
 	 */
 	public function head()
 	{
-		echo self::PL_HEAD;
+		echo self::PH_HEAD;
 	}
 
 	/**
 	 * Registers the named asset bundle.
 	 * All dependent asset bundles will be registered.
 	 * @param string $name the name of the asset bundle.
+	 * @return AssetBundle the registered asset bundle instance
 	 * @throws InvalidConfigException if the asset bundle does not exist or a circular dependency is detected
 	 */
 	public function registerAssetBundle($name)
@@ -582,6 +585,7 @@ class View extends Component
 		} elseif ($this->assetBundles[$name] === false) {
 			throw new InvalidConfigException("A circular dependency is detected for bundle '$name'.");
 		}
+		return $this->assetBundles[$name];
 	}
 
 	/**
@@ -665,7 +669,7 @@ class View extends Component
 		$key = $key ?: md5($js);
 		$this->js[$position][$key] = $js;
 		if ($position === self::POS_READY) {
-			$this->registerAssetBundle('yii/jquery');
+			JqueryAsset::register($this);
 		}
 	}
 
diff --git a/framework/yii/bootstrap/AffixAsset.php b/framework/yii/bootstrap/AffixAsset.php
new file mode 100644
index 0000000..f92315f
--- /dev/null
+++ b/framework/yii/bootstrap/AffixAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AffixAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-affix.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/AlertAsset.php b/framework/yii/bootstrap/AlertAsset.php
new file mode 100644
index 0000000..13e8f39
--- /dev/null
+++ b/framework/yii/bootstrap/AlertAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class AlertAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-alert.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/BootstrapAsset.php b/framework/yii/bootstrap/BootstrapAsset.php
new file mode 100644
index 0000000..5e5f756
--- /dev/null
+++ b/framework/yii/bootstrap/BootstrapAsset.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class BootstrapAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $css = array(
+		'css/bootstrap.css',
+	);
+}
diff --git a/framework/yii/bootstrap/ButtonAsset.php b/framework/yii/bootstrap/ButtonAsset.php
new file mode 100644
index 0000000..378d59e
--- /dev/null
+++ b/framework/yii/bootstrap/ButtonAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ButtonAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-button.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/CarouselAsset.php b/framework/yii/bootstrap/CarouselAsset.php
new file mode 100644
index 0000000..c75a619
--- /dev/null
+++ b/framework/yii/bootstrap/CarouselAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class CarouselAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-carousel.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/CollapseAsset.php b/framework/yii/bootstrap/CollapseAsset.php
new file mode 100644
index 0000000..6a60ec0
--- /dev/null
+++ b/framework/yii/bootstrap/CollapseAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class CollapseAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-collapse.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/DropdownAsset.php b/framework/yii/bootstrap/DropdownAsset.php
new file mode 100644
index 0000000..29d9dee
--- /dev/null
+++ b/framework/yii/bootstrap/DropdownAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class DropdownAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-dropdown.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/ModalAsset.php b/framework/yii/bootstrap/ModalAsset.php
new file mode 100644
index 0000000..cff10b1
--- /dev/null
+++ b/framework/yii/bootstrap/ModalAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ModalAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-modal.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/Nav.php b/framework/yii/bootstrap/Nav.php
index 7b003f4..cea83d8 100644
--- a/framework/yii/bootstrap/Nav.php
+++ b/framework/yii/bootstrap/Nav.php
@@ -88,7 +88,7 @@ class Nav extends Widget
 	public function run()
 	{
 		echo $this->renderItems();
-		$this->getView()->registerAssetBundle('yii/bootstrap');
+		BootstrapAsset::register($this->getView());
 	}
 
 	/**
diff --git a/framework/yii/bootstrap/NavBar.php b/framework/yii/bootstrap/NavBar.php
index 337e449..f801df5 100644
--- a/framework/yii/bootstrap/NavBar.php
+++ b/framework/yii/bootstrap/NavBar.php
@@ -119,7 +119,11 @@ class NavBar extends Widget
 		echo Html::beginTag('div', $this->options);
 		echo $this->renderItems();
 		echo Html::endTag('div');
-		$this->getView()->registerAssetBundle(self::$responsive ? 'yii/bootstrap/responsive' : 'yii/bootstrap');
+		if (self::$responsive) {
+			ResponsiveAsset::register($this->getView());
+		} else {
+			BootstrapAsset::register($this->getView());
+		}
 	}
 
 	/**
@@ -136,7 +140,7 @@ class NavBar extends Widget
 		$brand = Html::a($this->brandLabel, $this->brandUrl, $this->brandOptions);
 
 		if (self::$responsive) {
-			$this->getView()->registerAssetBundle('yii/bootstrap/collapse');
+			CollapseAsset::register($this->getView());
 			$contents = Html::tag('div',
 					$this->renderToggleButton() .
 					$brand . "\n" .
diff --git a/framework/yii/bootstrap/PopoverAsset.php b/framework/yii/bootstrap/PopoverAsset.php
new file mode 100644
index 0000000..a28d6c4
--- /dev/null
+++ b/framework/yii/bootstrap/PopoverAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class PopoverAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-popover.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TooltipAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/Progress.php b/framework/yii/bootstrap/Progress.php
index ae44619..57046b1 100644
--- a/framework/yii/bootstrap/Progress.php
+++ b/framework/yii/bootstrap/Progress.php
@@ -105,7 +105,11 @@ class Progress extends Widget
 		echo Html::beginTag('div', $this->options) . "\n";
 		echo $this->renderProgress() . "\n";
 		echo Html::endTag('div') . "\n";
-		$this->getView()->registerAssetBundle(static::$responsive ? 'yii/bootstrap/responsive' : 'yii/bootstrap');
+		if (self::$responsive) {
+			ResponsiveAsset::register($this->getView());
+		} else {
+			BootstrapAsset::register($this->getView());
+		}
 	}
 
 	/**
diff --git a/framework/yii/bootstrap/ResponsiveAsset.php b/framework/yii/bootstrap/ResponsiveAsset.php
new file mode 100644
index 0000000..fb8138b
--- /dev/null
+++ b/framework/yii/bootstrap/ResponsiveAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ResponsiveAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $css = array(
+		'css/bootstrap-responsive.css',
+	);
+	public $depends = array(
+		'yii\bootstrap\BootstrapAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/ScrollspyAsset.php b/framework/yii/bootstrap/ScrollspyAsset.php
new file mode 100644
index 0000000..8a52694
--- /dev/null
+++ b/framework/yii/bootstrap/ScrollspyAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ScrollspyAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-scrollspy.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/TabAsset.php b/framework/yii/bootstrap/TabAsset.php
new file mode 100644
index 0000000..51ff844
--- /dev/null
+++ b/framework/yii/bootstrap/TabAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class TabAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-tab.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/TooltipAsset.php b/framework/yii/bootstrap/TooltipAsset.php
new file mode 100644
index 0000000..5f96215
--- /dev/null
+++ b/framework/yii/bootstrap/TooltipAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class TooltipAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-tooltip.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/TransitionAsset.php b/framework/yii/bootstrap/TransitionAsset.php
new file mode 100644
index 0000000..b04cef0
--- /dev/null
+++ b/framework/yii/bootstrap/TransitionAsset.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class TransitionAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-transition.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/TypeAhead.php b/framework/yii/bootstrap/Typeahead.php
similarity index 97%
rename from framework/yii/bootstrap/TypeAhead.php
rename to framework/yii/bootstrap/Typeahead.php
index 0704404..8fb2fa4 100644
--- a/framework/yii/bootstrap/TypeAhead.php
+++ b/framework/yii/bootstrap/Typeahead.php
@@ -13,7 +13,7 @@ use yii\base\Model;
 use yii\helpers\Html;
 
 /**
- * TypeAhead renders a typehead bootstrap javascript component.
+ * Typeahead renders a typehead bootstrap javascript component.
  *
  * For example,
  *
@@ -42,7 +42,7 @@ use yii\helpers\Html;
  * @author Antonio Ramirez <amigo.cobos@gmail.com>
  * @since 2.0
  */
-class TypeAhead extends Widget
+class Typeahead extends Widget
 {
 	/**
 	 * @var \yii\base\Model the data model that this widget is associated with
diff --git a/framework/yii/bootstrap/TypeaheadAsset.php b/framework/yii/bootstrap/TypeaheadAsset.php
new file mode 100644
index 0000000..c67abae
--- /dev/null
+++ b/framework/yii/bootstrap/TypeaheadAsset.php
@@ -0,0 +1,26 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\bootstrap;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class TypeaheadAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/bootstrap/assets';
+	public $js = array(
+		'js/bootstrap-typeahead.js',
+	);
+	public $depends = array(
+		'yii\bootstrap\TransitionAsset',
+		'yii\bootstrap\BootstrapAsset',
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/bootstrap/Widget.php b/framework/yii/bootstrap/Widget.php
index 004f040..7636239 100644
--- a/framework/yii/bootstrap/Widget.php
+++ b/framework/yii/bootstrap/Widget.php
@@ -65,8 +65,14 @@ class Widget extends \yii\base\Widget
 	{
 		$id = $this->options['id'];
 		$view = $this->getView();
-		$view->registerAssetBundle(static::$responsive ? 'yii/bootstrap/responsive' : 'yii/bootstrap');
-		$view->registerAssetBundle("yii/bootstrap/$name");
+		if (self::$responsive) {
+			ResponsiveAsset::register($view);
+		} else {
+			BootstrapAsset::register($view);
+		}
+		/** @var \yii\web\AssetBundle $assetClass */
+		$assetClass = 'yii\bootstrap\\' . ucfirst($name);
+		$assetClass::register($view);
 
 		if ($this->clientOptions !== false) {
 			$options = empty($this->clientOptions) ? '' : Json::encode($this->clientOptions);
diff --git a/framework/yii/bootstrap/assets.php b/framework/yii/bootstrap/assets.php
index 0c4a6bc..c61e1fa 100644
--- a/framework/yii/bootstrap/assets.php
+++ b/framework/yii/bootstrap/assets.php
@@ -6,108 +6,19 @@
  */
 
 return array(
-	'yii/bootstrap' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'css' => array(
-			YII_DEBUG ? 'css/bootstrap.css' : 'css/bootstrap.min.css',
-		),
-	),
-	'yii/bootstrap/responsive' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'css' => array(
-			YII_DEBUG ? 'css/bootstrap-responsive.css' : 'css/bootstrap-responsive.min.css',
-		),
-		'depends' => array('yii/bootstrap'),
-	),
-	'yii/bootstrap/affix' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-affix.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/alert' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-alert.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/button' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-button.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/carousel' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-carousel.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/collapse' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-collapse.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/dropdown' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-dropdown.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/modal' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-modal.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/popover' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-popover.js',
-		),
-		'depends' => array('yii/bootstrap/tooltip'),
-	),
-	'yii/bootstrap/scrollspy' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-scrollspy.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/tab' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-tab.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/tooltip' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-tooltip.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
-	'yii/bootstrap/transition' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-transition.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap'),
-	),
-	'yii/bootstrap/typeahead' => array(
-		'sourcePath' => __DIR__ . '/assets',
-		'js' => array(
-			'js/bootstrap-typeahead.js',
-		),
-		'depends' => array('yii/jquery', 'yii/bootstrap', 'yii/bootstrap/transition'),
-	),
+	yii\bootstrap\BootstrapAsset::className(),
+	yii\bootstrap\ResponsiveAsset::className(),
+	yii\bootstrap\DropdownAsset::className(),
+	yii\bootstrap\TransitionAsset::className(),
+	yii\bootstrap\AffixAsset::className(),
+	yii\bootstrap\AlertAsset::className(),
+	yii\bootstrap\ButtonAsset::className(),
+	yii\bootstrap\CarouselAsset::className(),
+	yii\bootstrap\CollapseAsset::className(),
+	yii\bootstrap\ModalAsset::className(),
+	yii\bootstrap\PopoverAsset::className(),
+	yii\bootstrap\TooltipAsset::className(),
+	yii\bootstrap\ScrollspyAsset::className(),
+	yii\bootstrap\TabAsset::className(),
+	yii\bootstrap\TypeaheadAsset::className(),
 );
diff --git a/framework/yii/debug/DebugAsset.php b/framework/yii/debug/DebugAsset.php
new file mode 100644
index 0000000..ab02680
--- /dev/null
+++ b/framework/yii/debug/DebugAsset.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\debug;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class DebugAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/debug/assets';
+	public $css = array(
+		'main.css',
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+		'yii\bootstrap\ResponsiveAsset',
+	);
+}
diff --git a/framework/yii/debug/views/default/index.php b/framework/yii/debug/views/default/index.php
index c76d864..0c482ad 100644
--- a/framework/yii/debug/views/default/index.php
+++ b/framework/yii/debug/views/default/index.php
@@ -7,7 +7,6 @@ use yii\helpers\Html;
  * @var array $manifest
  */
 
-$this->registerAssetBundle('yii/bootstrap/dropdown');
 $this->title = 'Yii Debugger';
 ?>
 <div class="default-index">
diff --git a/framework/yii/debug/views/default/view.php b/framework/yii/debug/views/default/view.php
index 1d2c760..f43b1ad 100644
--- a/framework/yii/debug/views/default/view.php
+++ b/framework/yii/debug/views/default/view.php
@@ -11,8 +11,8 @@ use yii\helpers\Html;
  * @var \yii\debug\Panel $activePanel
  */
 
-$this->registerAssetBundle('yii/bootstrap/dropdown');
 $this->title = 'Yii Debugger';
+yii\bootstrap\DropdownAsset::register($this);
 ?>
 <div class="default-view">
 	<div class="navbar">
diff --git a/framework/yii/debug/views/layouts/main.php b/framework/yii/debug/views/layouts/main.php
index 5c8a735..8875878 100644
--- a/framework/yii/debug/views/layouts/main.php
+++ b/framework/yii/debug/views/layouts/main.php
@@ -5,7 +5,7 @@
  */
 use yii\helpers\Html;
 
-Yii::$app->getView()->registerAssetBundle('yii/debug');
+yii\debug\DebugAsset::register($this);
 ?>
 <!DOCTYPE html>
 <html>
diff --git a/framework/yii/validators/BooleanValidator.php b/framework/yii/validators/BooleanValidator.php
index 67a64f6..d1e81b8 100644
--- a/framework/yii/validators/BooleanValidator.php
+++ b/framework/yii/validators/BooleanValidator.php
@@ -102,7 +102,7 @@ class BooleanValidator extends Validator
 			$options['strict'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.boolean(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/CaptchaValidator.php b/framework/yii/validators/CaptchaValidator.php
index 7721067..2a16f57 100644
--- a/framework/yii/validators/CaptchaValidator.php
+++ b/framework/yii/validators/CaptchaValidator.php
@@ -116,7 +116,7 @@ class CaptchaValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.captcha(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/CompareValidator.php b/framework/yii/validators/CompareValidator.php
index c94577c..8c9e587 100644
--- a/framework/yii/validators/CompareValidator.php
+++ b/framework/yii/validators/CompareValidator.php
@@ -205,7 +205,7 @@ class CompareValidator extends Validator
 			'{compareValue}' => $compareValue,
 		)));
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.compare(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/EmailValidator.php b/framework/yii/validators/EmailValidator.php
index 292da88..c3d8480 100644
--- a/framework/yii/validators/EmailValidator.php
+++ b/framework/yii/validators/EmailValidator.php
@@ -139,9 +139,9 @@ class EmailValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		if ($this->enableIDN) {
-			$view->registerAssetBundle('yii/punycode');
+			PunycodeAsset::register($view);
 		}
 		return 'yii.validation.email(value, messages, ' . Json::encode($options) . ');';
 	}
diff --git a/framework/yii/validators/NumberValidator.php b/framework/yii/validators/NumberValidator.php
index 3bcc6ce..2fee133 100644
--- a/framework/yii/validators/NumberValidator.php
+++ b/framework/yii/validators/NumberValidator.php
@@ -151,7 +151,7 @@ class NumberValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.number(value, messages, ' . Json::encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/PunycodeAsset.php b/framework/yii/validators/PunycodeAsset.php
new file mode 100644
index 0000000..08d3fb4
--- /dev/null
+++ b/framework/yii/validators/PunycodeAsset.php
@@ -0,0 +1,21 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\validators;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class PunycodeAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'punycode/punycode.js',
+	);
+}
diff --git a/framework/yii/validators/RangeValidator.php b/framework/yii/validators/RangeValidator.php
index 90256df..f89d420 100644
--- a/framework/yii/validators/RangeValidator.php
+++ b/framework/yii/validators/RangeValidator.php
@@ -103,7 +103,7 @@ class RangeValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.range(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/RegularExpressionValidator.php b/framework/yii/validators/RegularExpressionValidator.php
index 72a5a74..4ae2099 100644
--- a/framework/yii/validators/RegularExpressionValidator.php
+++ b/framework/yii/validators/RegularExpressionValidator.php
@@ -112,7 +112,7 @@ class RegularExpressionValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.regularExpression(value, messages, ' . Json::encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/RequiredValidator.php b/framework/yii/validators/RequiredValidator.php
index aedbe05..9ca0ecb 100644
--- a/framework/yii/validators/RequiredValidator.php
+++ b/framework/yii/validators/RequiredValidator.php
@@ -126,7 +126,7 @@ class RequiredValidator extends Validator
 			'{value}' => $object->$attribute,
 		)));
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.required(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/StringValidator.php b/framework/yii/validators/StringValidator.php
index e06354b..4cc9dba 100644
--- a/framework/yii/validators/StringValidator.php
+++ b/framework/yii/validators/StringValidator.php
@@ -170,7 +170,7 @@ class StringValidator extends Validator
 			$options['skipOnEmpty'] = 1;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		return 'yii.validation.string(value, messages, ' . json_encode($options) . ');';
 	}
 }
diff --git a/framework/yii/validators/UrlValidator.php b/framework/yii/validators/UrlValidator.php
index 18f2f45..aa3dad1 100644
--- a/framework/yii/validators/UrlValidator.php
+++ b/framework/yii/validators/UrlValidator.php
@@ -143,9 +143,9 @@ class UrlValidator extends Validator
 			$options['defaultScheme'] = $this->defaultScheme;
 		}
 
-		$view->registerAssetBundle('yii/validation');
+		ValidationAsset::register($view);
 		if ($this->enableIDN) {
-			$view->registerAssetBundle('yii/punycode');
+			PunycodeAsset::register($view);
 		}
 		return 'yii.validation.url(value, messages, ' . Json::encode($options) . ');';
 	}
diff --git a/framework/yii/validators/ValidationAsset.php b/framework/yii/validators/ValidationAsset.php
new file mode 100644
index 0000000..625e580
--- /dev/null
+++ b/framework/yii/validators/ValidationAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\validators;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ValidationAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'yii.validation.js',
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+	);
+}
diff --git a/framework/yii/web/AssetBundle.php b/framework/yii/web/AssetBundle.php
index daa533f..520dc8d 100644
--- a/framework/yii/web/AssetBundle.php
+++ b/framework/yii/web/AssetBundle.php
@@ -10,6 +10,7 @@ namespace yii\web;
 use Yii;
 use yii\base\InvalidConfigException;
 use yii\base\Object;
+use yii\base\View;
 
 /**
  * AssetBundle represents a collection of asset files, such as CSS, JS, images.
@@ -102,6 +103,15 @@ class AssetBundle extends Object
 	public $publishOptions = array();
 
 	/**
+	 * @param View $view
+	 * @return AssetBundle the registered asset bundle instance
+	 */
+	public static function register($view)
+	{
+		return $view->registerAssetBundle(get_called_class());
+	}
+
+	/**
 	 * Initializes the bundle.
 	 */
 	public function init()
@@ -150,7 +160,7 @@ class AssetBundle extends Object
 	 */
 	public function publish($am)
 	{
-		if ($this->sourcePath !== null) {
+		if ($this->sourcePath !== null && !isset($this->basePath, $this->baseUrl)) {
 			list ($this->basePath, $this->baseUrl) = $am->publish($this->sourcePath, $this->publishOptions);
 		}
 		$converter = $am->getConverter();
diff --git a/framework/yii/web/AssetManager.php b/framework/yii/web/AssetManager.php
index 5fe67f7..eeffb01 100644
--- a/framework/yii/web/AssetManager.php
+++ b/framework/yii/web/AssetManager.php
@@ -22,10 +22,11 @@ use yii\helpers\FileHelper;
 class AssetManager extends Component
 {
 	/**
-	 * @var array list of available asset bundles. The keys are the bundle names, and the values are the configuration
-	 * arrays for creating the [[AssetBundle]] objects.
+	 * @var array list of available asset bundles. The keys are the class names of the asset bundles,
+	 * and the values are either the configuration arrays for creating the [[AssetBundle]] objects
+	 * or the corresponding asset bundle instances.
 	 */
-	public $bundles;
+	public $bundles = array();
 	/**
 	 * @return string the root directory storing the published asset files.
 	 */
@@ -81,55 +82,29 @@ class AssetManager extends Component
 			$this->basePath = realpath($this->basePath);
 		}
 		$this->baseUrl = rtrim(Yii::getAlias($this->baseUrl), '/');
-
-		foreach (require(YII_PATH . '/assets.php') as $name => $bundle) {
-			if (!isset($this->bundles[$name])) {
-				$this->bundles[$name] = $bundle;
-			}
-		}
 	}
 
 	/**
-	 * Returns the named bundle.
-	 * This method will first look for the bundle in [[bundles]]. If not found,
-	 * it will attempt to find the bundle from an installed extension using the following procedure:
-	 *
-	 * 1. Convert the bundle into a path alias;
-	 * 2. Determine the root alias and use it to locate the bundle manifest file "assets.php";
-	 * 3. Look for the bundle in the manifest file.
+	 * Returns the named asset bundle.
 	 *
-	 * For example, given the bundle name "foo/button", the method will first convert it
-	 * into the path alias "@foo/button"; since "@foo" is the root alias, it will look
-	 * for the bundle manifest file "@foo/assets.php". The manifest file should return an array
-	 * that lists the bundles used by the "foo/button" extension. The array format is the same as [[bundles]].
+	 * This method will first look for the bundle in [[bundles]]. If not found,
+	 * it will treat `$name` as the class of the asset bundle and create a new instance of it.
 	 *
-	 * @param string $name the bundle name
-	 * @return AssetBundle the loaded bundle object. Null is returned if the bundle does not exist.
+	 * @param string $name the class name of the asset bundle
+	 * @return AssetBundle the asset bundle instance
+	 * @throws InvalidConfigException if $name does not refer to a valid asset bundle
 	 */
 	public function getBundle($name)
 	{
-		if (!isset($this->bundles[$name])) {
-			$rootAlias = Yii::getRootAlias("@$name");
-			if ($rootAlias !== false) {
-				$manifest = Yii::getAlias("$rootAlias/assets.php", false);
-				if ($manifest !== false && is_file($manifest)) {
-					foreach (require($manifest) as $bn => $config) {
-						$this->bundles[$bn] = $config;
-					}
-				}
-			}
-			if (!isset($this->bundles[$name])) {
-				return null;
-			}
-		}
-		if (is_array($this->bundles[$name])) {
-			$config = $this->bundles[$name];
-			if (!isset($config['class'])) {
-				$config['class'] = 'yii\\web\\AssetBundle';
+		if (isset($this->bundles[$name])) {
+			if (is_array($this->bundles[$name])) {
+				$this->bundles[$name] = Yii::createObject(array_merge(array('class' => $name), $this->bundles[$name]));
+			} elseif (!$this->bundles[$name] instanceof AssetBundle) {
+				throw new InvalidConfigException("Invalid asset bundle: $name");
 			}
-			$this->bundles[$name] = Yii::createObject($config);
+		} else {
+			$this->bundles[$name] = Yii::createObject($name);
 		}
-
 		return $this->bundles[$name];
 	}
 
@@ -142,9 +117,7 @@ class AssetManager extends Component
 	public function getConverter()
 	{
 		if ($this->_converter === null) {
-			$this->_converter = Yii::createObject(array(
-				'class' => 'yii\\web\\AssetConverter',
-			));
+			$this->_converter = Yii::createObject(AssetConverter::className());
 		} elseif (is_array($this->_converter) || is_string($this->_converter)) {
 			$this->_converter = Yii::createObject($this->_converter);
 		}
diff --git a/framework/yii/web/JqueryAsset.php b/framework/yii/web/JqueryAsset.php
new file mode 100644
index 0000000..4585acd
--- /dev/null
+++ b/framework/yii/web/JqueryAsset.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\web;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class JqueryAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'jquery.js',
+	);
+}
diff --git a/framework/yii/web/YiiAsset.php b/framework/yii/web/YiiAsset.php
new file mode 100644
index 0000000..8a4d77a
--- /dev/null
+++ b/framework/yii/web/YiiAsset.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\web;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class YiiAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'yii.js',
+	);
+	public $depends = array(
+		'yii\web\JqueryAsset',
+	);
+}
diff --git a/framework/yii/widgets/ActiveForm.php b/framework/yii/widgets/ActiveForm.php
index d844117..1d4be89 100644
--- a/framework/yii/widgets/ActiveForm.php
+++ b/framework/yii/widgets/ActiveForm.php
@@ -167,8 +167,9 @@ class ActiveForm extends Widget
 			$id = $this->options['id'];
 			$options = Json::encode($this->getClientOptions());
 			$attributes = Json::encode($this->attributes);
-			$this->getView()->registerAssetBundle('yii/form');
-			$this->getView()->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
+			$view = $this->getView();
+			ActiveFormAsset::register($view);
+			$view->registerJs("jQuery('#$id').yiiActiveForm($attributes, $options);");
 		}
 		echo Html::endForm();
 	}
diff --git a/framework/yii/widgets/ActiveFormAsset.php b/framework/yii/widgets/ActiveFormAsset.php
new file mode 100644
index 0000000..cbd3f9a
--- /dev/null
+++ b/framework/yii/widgets/ActiveFormAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\widgets;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class ActiveFormAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'yii.activeForm.js',
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+	);
+}
diff --git a/framework/yii/widgets/Captcha.php b/framework/yii/widgets/Captcha.php
index ffe8802..1c538fb 100644
--- a/framework/yii/widgets/Captcha.php
+++ b/framework/yii/widgets/Captcha.php
@@ -97,8 +97,9 @@ class Captcha extends InputWidget
 		$options = $this->getClientOptions();
 		$options = empty($options) ? '' : Json::encode($options);
 		$id = $this->imageOptions['id'];
-		$this->getView()->registerAssetBundle('yii/captcha');
-		$this->getView()->registerJs("jQuery('#$id').yiiCaptcha($options);");
+		$view = $this->getView();
+		CaptchaAsset::register($view);
+		$view->registerJs("jQuery('#$id').yiiCaptcha($options);");
 	}
 
 	/**
diff --git a/framework/yii/widgets/CaptchaAsset.php b/framework/yii/widgets/CaptchaAsset.php
new file mode 100644
index 0000000..4322e8e
--- /dev/null
+++ b/framework/yii/widgets/CaptchaAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\widgets;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class CaptchaAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'yii.captcha.js',
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+	);
+}
diff --git a/framework/yii/widgets/MaskedInput.php b/framework/yii/widgets/MaskedInput.php
index a5a23f5..35794b8 100644
--- a/framework/yii/widgets/MaskedInput.php
+++ b/framework/yii/widgets/MaskedInput.php
@@ -109,8 +109,9 @@ class MaskedInput extends InputWidget
 		}
 		$id = $this->options['id'];
 		$js .= "jQuery(\"#{$id}\").mask(\"{$this->mask}\"{$options});";
-		$this->getView()->registerAssetBundle('yii/maskedinput');
-		$this->getView()->registerJs($js);
+		$view = $this->getView();
+		MaskedInputAsset::register($view);
+		$view->registerJs($js);
 	}
 
 	/**
diff --git a/framework/yii/widgets/MaskedInputAsset.php b/framework/yii/widgets/MaskedInputAsset.php
new file mode 100644
index 0000000..d091505
--- /dev/null
+++ b/framework/yii/widgets/MaskedInputAsset.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright (c) 2008 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+namespace yii\widgets;
+use yii\web\AssetBundle;
+
+/**
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @since 2.0
+ */
+class MaskedInputAsset extends AssetBundle
+{
+	public $sourcePath = '@yii/assets';
+	public $js = array(
+		'jquery.maskedinput.js',
+	);
+	public $depends = array(
+		'yii\web\YiiAsset',
+	);
+}