Vue-cli2項目文件目錄解析

前言

不是原創,真的不是原創,主要我是根據CSDN的一篇文章和其餘平臺上的文章整理而來,在最後我會貼上全部原文的地址,下面正式進入正文。css

Vue-cli項目文件目錄結構

這個是Vue-cli2.0版本的文件目錄結構,整體來講就是以下圖的
imagehtml

build文件目錄

一、build.js文件: 是咱們完成項目以後須要運行的, 能夠將咱們的項目文件打包成 靜態文件,存放在項目根目錄的 dist 文件夾中(如今目錄裏尚未這個文件夾,npm run build的時候會自動生成),固然你能夠本身設置路徑,是在 config 文件夾中的 index.js 中改,能夠指定主頁,默認是 index.html。vue

'use strict' // 調用exports出來的一個函數 require('./check-versions')() // 全局環境變量的設置(默認生產模式) process.env.NODE_ENV = 'production' // ora,一個能夠在終端顯示spinner的插件,就是日誌輸出 const ora = require('ora') // rm,用於刪除文件或文件夾的插件 const rm = require('rimraf') // path,node中默認處理文件路徑的模塊 const path = require('path') // chalk,用於在控制檯輸出帶顏色字體的插件 const chalk = require('chalk') const webpack = require('webpack') // config,項目配置文件 const config = require('../config') // 加載生產包的配置 const webpackConfig = require('./webpack.prod.conf') const spinner = ora('building for production...') // 開啓loading動畫 spinner.start() // 首先將整個dist文件夾以及裏面的內容刪除,以避免遺留舊的沒用的文件 // 刪除完成後纔開始webpack構建打包 rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { if(err) throw err // 執行webpack構建打包,完成以後在終端輸出構建完成的相關信息或者輸出報錯信息並退出程序 webpack(webpackConfig, (err, stats) => { spinner.stop() if(err) throw err process.stdout.write(stats.toString({ colors: true, modules: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. children: false, chunks: false, chunkModules: false }) + '\n\n') if(stats.hasErrors()) { console.log(chalk.red(' Build failed with errors.\n')) process.exit(1) } console.log(chalk.cyan(' Build complete.\n')) console.log(chalk.yellow(' Tip: built files are meant to be served over an HTTP server.\n' + ' Opening index.html over file:// won\'t work.\n')) }) })

二、check-version.js文件: 主要是檢查一些所依賴的工具的版本是否適用,如nodejs、npm,若版本過低則會提示出來。node

'use strict' // chalk,用於在控制檯輸出帶顏色字體的插件 const chalk = require('chalk') // 引入版本檢查工具 const semver = require('semver') const packageConfig = require('../package.json') const shell = require('shelljs') function exec(cmd) { return require('child_process').execSync(cmd).toString().trim() } const versionRequirements = [{ name: 'node', currentVersion: semver.clean(process.version), versionRequirement: packageConfig.engines.node }] if(shell.which('npm')) { versionRequirements.push({ name: 'npm', currentVersion: exec('npm --version'), versionRequirement: packageConfig.engines.npm }) } module.exports = function() { const warnings = [] for(let i = 0; i < versionRequirements.length; i++) { const mod = versionRequirements[i] // 檢查版本是否合法 if(!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { warnings.push(mod.name + ': ' + chalk.red(mod.currentVersion) + ' should be ' + chalk.green(mod.versionRequirement)) } } if(warnings.length) { console.log('') console.log(chalk.yellow('To use this template, you must update following to modules:')) console.log() for(let i = 0; i < warnings.length; i++) { const warning = warnings[i] console.log(' ' + warning) } console.log() process.exit(1) } }

三、utils.js文件: 一個功能模塊,以便於解析各類格式的css,如 less,sass 什麼的。webpack

'use strict' const path = require('path') const config = require('../config') // 這裏用來提取css樣式 // extract-text-webpack-plugin能夠提取bundle中的特定文本,將提取後的文本單獨存放到另外的文件 const ExtractTextPlugin = require('extract-text-webpack-plugin') const packageConfig = require('../package.json') // 資源文件的存放路徑 exports.assetsPath = function(_path) { const assetsSubDirectory = process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path) } // 生成css、sass、scss等各類用來編寫樣式的語言所對應的loader配置 exports.cssLoaders = function(options) { options = options || {} // css-loader配置 const cssLoader = { loader: 'css-loader', options: { // 是否使用source-map sourceMap: options.sourceMap } } const postcssLoader = { loader: 'postcss-loader', options: { sourceMap: options.sourceMap } } // generate loader string to be used with extract text plugin // 生成各類loader配置,而且配置了extract-text-pulgin function generateLoaders(loader, loaderOptions) { const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] // 例如generateLoaders('less'),這裏就會push一個less-loader // less-loader先將less編譯成css,而後再由css-loader去處理css // 其餘sass、scss等語言也是同樣的過程 if(loader) { loaders.push({ loader: loader + '-loader', options: Object.assign({}, loaderOptions, { sourceMap: options.sourceMap }) }) } // Extract CSS when that option is specified // (which is the case during production build) if(options.extract) { // 配置extract-text-plugin提取樣式 return ExtractTextPlugin.extract({ use: loaders, fallback: 'vue-style-loader' }) } else { // 無需提取樣式則簡單使用vue-style-loader配合各類樣式loader去處理<style>裏面的樣式 return ['vue-style-loader'].concat(loaders) } } // https://vue-loader.vuejs.org/en/configurations/extract-css.html // 獲得各類不一樣處理樣式的語言所對應的loader return { css: generateLoaders(), postcss: generateLoaders(), less: generateLoaders('less'), sass: generateLoaders('sass', { indentedSyntax: true }), scss: generateLoaders('sass'), stylus: generateLoaders('stylus'), styl: generateLoaders('stylus') } } // Generate loaders for standalone style files (outside of .vue) // 生成處理單獨的.css、.sass、.scss等樣式文件的規則 exports.styleLoaders = function(options) { const output = [] const loaders = exports.cssLoaders(options) for(const extension in loaders) { const loader = loaders[extension] output.push({ test: new RegExp('\\.' + extension + '$'), use: loader }) } return output } exports.createNotifierCallback = () => { const notifier = require('node-notifier') return(severity, errors) => { if(severity !== 'error') return const error = errors[0] const filename = error.file && error.file.split('!').pop() notifier.notify({ title: packageConfig.name, message: severity + ': ' + error.name, subtitle: filename || '', icon: path.join(__dirname, 'logo.png') }) } }

四、vue-loader.conf.js文件: 用來解決各類css文件的,定義了諸如css,less,sass之類的和樣式有關的loadergit

'use strict'
const utils = require('./utils')
const config = require('../config')
const isProduction = process.env.NODE_ENV === 'production'
const sourceMapEnabled = isProduction ? config.build.productionSourceMap : config.dev.cssSourceMap
module.exports = {
  loaders: utils.cssLoaders({
    sourceMap: sourceMapEnabled,
    extract: isProduction
  }),
  cssSourceMap: sourceMapEnabled,
  cacheBusting: config.dev.cacheBusting,
  transformToRequire: {
    video: ['src', 'poster'],
    source: 'src',
    img: 'src',
    image: 'xlink:href'
  }
}

五、webpack.base.conf.js文件: webpack基礎配置,定義入口文件路徑和輸出文件路徑,以及各類文件轉義的規則,是一個核心的配置文件es6

'use strict' const path = require('path') const utils = require('./utils') const config = require('../config') const vueLoaderConfig = require('./vue-loader.conf') // 獲取絕對路徑 function resolve(dir) { return path.join(__dirname, '..', dir) } // 定義一下代碼檢測的規則 const createLintingRule = () => ({ test: /\.(js|vue)$/, loader: 'eslint-loader', enforce: 'pre', include: [resolve('src'), resolve('test')], options: { formatter: require('eslint-friendly-formatter'), emitWarning: !config.dev.showEslintErrorsInOverlay } }) module.exports = { // 基礎上下文 context: path.resolve(__dirname, '../'), // webpack的入口文件 entry: { app: './src/main.js' }, // webpack的輸出文件 output: { // 指定路徑 path: config.build.assetsRoot, // 指定輸出名 filename: '[name].js', publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath }, /**  * 當webpack試圖去加載模塊的時候,它默認是查找以 .js 結尾的文件的,  * 它並不知道 .vue 結尾的文件是什麼鬼玩意兒,  * 因此咱們要在配置文件中告訴webpack,  * 遇到 .vue 結尾的也要去加載,  * 添加 resolve 配置項,以下:  */ resolve: { extensions: ['.js', '.vue', '.json'], // 建立別名 alias: { 'vue$': 'vue/dist/vue.esm.js', '@': resolve('src'), } }, // 不一樣類型模塊的處理規則 就是用不一樣的loader處理不一樣的文件 module: { rules: [{ // 對全部.vue文件使用vue-loader進行編譯 test: /\.vue$/, loader: 'vue-loader', options: vueLoaderConfig }, { // 對src和test文件夾下的.js文件使用babel-loader將es6+的代碼轉成es5 test: /\.js$/, loader: 'babel-loader', include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] }, { // 對圖片資源文件使用url-loader test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url-loader', options: { // 小於10K的圖片轉成base64編碼的dataURL字符串寫到代碼中 limit: 10000, // 其餘的圖片轉移到靜態資源文件夾 name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { // 對多媒體資源文件使用url-loader test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, loader: 'url-loader', options: { // 小於10K的資源轉成base64編碼的dataURL字符串寫到代碼中 limit: 10000, // 其餘的資源轉移到靜態資源文件夾 name: utils.assetsPath('media/[name].[hash:7].[ext]') } }, { // 對字體資源文件使用url-loader test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url-loader', options: { limit: 10000, // hash:7 表明 7位數的 hash name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } }] }, node: { // prevent webpack from injecting useless setImmediate polyfill because Vue // source contains it (although only uses it if it's native). setImmediate: false, // prevent webpack from injecting mocks to Node native modules // that does not make sense for the client dgram: 'empty', fs: 'empty', net: 'empty', tls: 'empty', child_process: 'empty' } }

六、webpack.dev.conf.js文件: webpack開發環境配置,構建開發本地服務器github

'use strict' const utils = require('./utils') const webpack = require('webpack') // 基本配置的參數 const config = require('../config') // webpack-merge是一個能夠合併數組和對象的插件 const merge = require('webpack-merge') const path = require('path') // webpack基本配置文件(開發和生產環境公用部分 const baseWebpackConfig = require('./webpack.base.conf') const CopyWebpackPlugin = require('copy-webpack-plugin') // html-webpack-plugin用於將webpack編譯打包後的產品文件注入到html模板中 // 即在index.html裏面加上<link>和<script>標籤引用webpack打包後的文件 const HtmlWebpackPlugin = require('html-webpack-plugin') // friendly-errors-webpack-plugin用於更友好地輸出webpack的警告、錯誤等信息 const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') // 自動檢索下一個可用端口 const portfinder = require('portfinder') const HOST = process.env.HOST // 讀取系統環境變量的port const PORT = process.env.PORT && Number(process.env.PORT) // 合併baseWebpackConfig配置 const devWebpackConfig = merge(baseWebpackConfig, { module: { // 對一些獨立的css文件以及它的預處理文件作一個編譯 rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) }, // cheap-module-eval-source-map is faster for development devtool: config.dev.devtool, // these devServer options should be customized in /config/index.js // webpack-dev-server服務器配置 devServer: { // console 控制檯顯示的消息,可能的值有 none, error, warning 或者 info clientLogLevel: 'warning', historyApiFallback: { rewrites: [{ from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') },], }, // 開啓熱模塊加載 hot: true, contentBase: false, // since we use CopyWebpackPlugin. compress: true, // process.env 優先 host: HOST || config.dev.host, // process.env 優先 port: PORT || config.dev.port, open: config.dev.autoOpenBrowser, overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false, publicPath: config.dev.assetsPublicPath, // 代理設置 proxy: config.dev.proxyTable, quiet: true, // necessary for FriendlyErrorsPlugin // 啓用 Watch模式。這意味着在初始構建以後,webpack將繼續監放任何已解析文件的更改 watchOptions: { // 經過傳遞 true開啓 polling,或者指定毫秒爲單位進行輪詢。默認爲false poll: config.dev.poll, } }, plugins: [ new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }), // 模塊熱替換它容許在運行時更新各類模塊,而無需進行徹底刷新 new webpack.HotModuleReplacementPlugin(), // HMR shows correct file names in console on update. new webpack.NamedModulesPlugin(), // 跳過編譯時出錯的代碼並記錄下來,主要做用是使編譯後運行時的包不出錯 new webpack.NoEmitOnErrorsPlugin(), // https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ // 指定編譯後生成的html文件名 filename: 'index.html', // 須要處理的模板 template: 'index.html', // 打包過程當中輸出的js、css的路徑添加到html文件中 // css文件插入到head中 // js文件插入到body中,可能的選項有 true, 'head', 'body', false inject: true }), // copy custom static assets new CopyWebpackPlugin([{ from: path.resolve(__dirname, '../static'), to: config.dev.assetsSubDirectory, ignore: ['.*'] }]) ] }) module.exports = new Promise((resolve, reject) => { // 獲取當前設定的端口 portfinder.basePort = process.env.PORT || config.dev.port portfinder.getPort((err, port) => { if(err) { reject(err) } else { // publish the new Port, necessary for e2e tests // 發佈新的端口,對於e2e測試 process.env.PORT = port // add port to devServer config devWebpackConfig.devServer.port = port // Add FriendlyErrorsPlugin devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ compilationSuccessInfo: { messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], }, onErrors: config.dev.notifyOnErrors ? utils.createNotifierCallback() : undefined })) resolve(devWebpackConfig) } }) })

七、webpack.prod.conf.js文件: webpack生產環境配置web

'use strict' // node內部默認的文件路徑處理模塊 const path = require('path') const utils = require('./utils') const webpack = require('webpack') const config = require('../config') // 文件配置合併的插件,做用是使生產文件webpack.prod.conf和 // 開發文件webpack.dev.conf文件繼承webpack.base.conf文件部分 const merge = require('webpack-merge') const baseWebpackConfig = require('./webpack.base.conf') // copy-webpack-plugin,用於將static中的靜態文件複製到產品文件夾dist const CopyWebpackPlugin = require('copy-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') const ExtractTextPlugin = require('extract-text-webpack-plugin') // optimize-css-assets-webpack-plugin,用於優化和最小化css資源 const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') // uglifyJs 混淆js插件 const UglifyJsPlugin = require('uglifyjs-webpack-plugin') const env = require('../config/prod.env') const webpackConfig = merge(baseWebpackConfig, { module: { // 樣式文件的處理規則,對css/sass/scss等不一樣內容使用相應的styleLoaders // 由utils配置出各類類型的預處理語言所須要使用的loader,例如sass須要使用sass-loader rules: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true, usePostCSS: true }) }, // 一個開發工具,指定文件格式 devtool: config.build.productionSourceMap ? config.build.devtool : false, // webpack輸出路徑和命名規則 output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, plugins: [ // http://vuejs.github.io/vue-loader/en/workflow/production.html new webpack.DefinePlugin({ 'process.env': env }), // 優化壓縮JS代碼 new UglifyJsPlugin({ uglifyOptions: { compress: { // 不保留警告 warnings: false } }, sourceMap: config.build.productionSourceMap, parallel: true }), // extract css into its own file // 將css提取到單獨的文件,插入到HTML文件中,減小請求數 new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), // Setting the following option to `false` will not extract CSS from codesplit chunks. // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 allChunks: true, }), // Compress extracted CSS. We are using this plugin so that possible // duplicated CSS from different components can be deduped. // 優化、最小化css代碼,若是隻簡單使用extract-text-plugin可能會形成css重複 // 具體緣由能夠看npm上面optimize-css-assets-webpack-plugin的介紹 new OptimizeCSSPlugin({ cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true } }), // generate dist index.html with correct asset hash for caching. // you can customize output by editing /index.html // see https://github.com/ampedandwired/html-webpack-plugin // 將產品文件所有插入到index.html new HtmlWebpackPlugin({ filename: config.build.index, template: 'index.html', inject: true, minify: { // 刪除index.html中的註釋 removeComments: true, // 刪除index.html中的空格 collapseWhitespace: true, // 刪除各類html標籤屬性值的雙引號 removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin // 注入依賴的時候按照依賴前後順序進行注入,好比,須要先注入vendor.js,再注入app.js chunksSortMode: 'dependency' }), // keep module.id stable when vendor modules does not change new webpack.HashedModuleIdsPlugin(), // enable scope hoisting new webpack.optimize.ModuleConcatenationPlugin(), // split vendor js into its own file // 將全部從node_modules中引入的js提取到vendor.js,即抽取庫文件 new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks(module) { // any required modules inside node_modules are extracted to vendor return(module.resource && /\.js$/.test(module.resource) && module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0) } }), // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated // 從vendor中提取出manifest,緣由如上 new webpack.optimize.CommonsChunkPlugin({ name: 'manifest', minChunks: Infinity }), // This instance extracts shared chunks from code splitted chunks and bundles them // in a separate chunk, similar to the vendor chunk // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk new webpack.optimize.CommonsChunkPlugin({ name: 'app', async: 'vendor-async', children: true, minChunks: 3 }), // copy custom static assets // 將static文件夾裏面的靜態資源複製到dist/static new CopyWebpackPlugin([{ from: path.resolve(__dirname, '../static'), to: config.build.assetsSubDirectory, ignore: ['.*'] }]) ] }) // 若是開啓了產品gzip壓縮,則利用插件將構建後的產品文件進行壓縮 if(config.build.productionGzip) { // 一個用於壓縮的webpack插件 const CompressionWebpackPlugin = require('compression-webpack-plugin') webpackConfig.plugins.push(new CompressionWebpackPlugin({ asset: '[path].gz[query]', // 壓縮算法 algorithm: 'gzip', test: new RegExp('\\.(' + config.build.productionGzipExtensions.join('|') + ')$'), threshold: 10240, minRatio: 0.8 })) } // 若是啓動了report,則經過插件給出webpack構建打包後的產品文件分析報告 if(config.build.bundleAnalyzerReport) { const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin webpackConfig.plugins.push(new BundleAnalyzerPlugin()) } module.exports = webpackConfig

config文件目錄

一、dev.env.js 文件: 開發環境變量配置算法

'use strict' const merge = require('webpack-merge') const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"' })

二、index.js 文件: 項目一些配置變量

'use strict'
// Template version: 1.3.1
// see http://vuejs-templates.github.io/webpack for documentation.
const path = require('path')
module.exports = {
  dev: {
    // Paths
    assetsSubDirectory: 'static',
    assetsPublicPath: './',
    proxyTable: {},
    // Various Dev Server sett
    // can be overwritten by process.env.HOSTings
    host: 'lo
    // can be overwritten by process.env.PORT, if port is in use, a free one will be determinedcalhost',
    port: 8080,
    autoOpenBrowser: false,
    errorOverlay: true,
    notifyOnErrors: true,
    // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
    poll: false,
    /**
     * Source Maps
     */
    // https://webpack.js.org/configuration/devtool/#development
    devtool: 'cheap-module-eval-source-map',
    // If you have problems debugging vue-files in devtools,
    // set this to false - it *may* help
    // https://vue-loader.vuejs.org/en/options.html#cachebusting
    cacheBusting: true,
    cssSourceMap: true
  },
  build: {
    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),
    // Paths
    // npm run build文件輸出目錄以及文件名
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    // 打完包後輸出的路徑,有用的一個屬性,能夠把值設置爲baidu.com看看
    assetsPublicPath: './',
    /**
     * Source Maps
     */
    // 開啓調試模式
    productionSourceMap: true,
    // https://webpack.js.org/configuration/devtool/#production
    devtool: '#source-map',
    // Gzip off by default as many popular static hosts such as
    // Surge or Netlify already gzip all static assets for you.
    // Before setting to `true`, make sure to:
    // npm install --save-dev compression-webpack-plugin
    productionGzip: false,
    productionGzipExtensions: ['js', 'css'],
    // Run the build command with an extra argument to
    // View the bundle analyzer report after build finishes:
    // `npm run build --report`
    // Set to `true` or `false` to always turn it on or off
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

三、prod.env.js文件: 生產環境變量配置

'use strict' module.exports = { NODE_ENV: '"production"' }

src文件目錄

這是源碼目錄,存放了vue全部的組件、vue路由管理、頁面入口文件和程序入口文件。這個目錄裏面包含的東西並不難理解,在這裏就不細說了。

static文件目錄

這是靜態文件存放目錄,主要放一些圖片和mock的json數據等。也沒啥好細說的,並且通常開發都會爲了方便起見而把靜態文件放在相關的組件裏面。

package.json文件

這是項目的配置文件,定義了項目的基本信息以及項目的相關包依賴,npm運行命令等。在這個文件中,scripts裏面定義的是一些比較長的命令,用node去執行一段命令,好比npm run dev,其實就是執行

webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

這句話的意思是利用webpack-dev-server讀取webpack.dev.conf.js信息並啓動一個本地服務。

尾聲

對於不少require進來的模塊不是很理解的話,能夠前往這裏查看各個模塊的含義。

參考資料

Vue-cli項目文件目錄解析

一、這多是vue-cli最全的解析了
二、深刻理解Vue-cli搭建項目後的目錄結構探祕

 

轉載:https://github.com/CruxF/VueNode-Mongo/issues/1

相關文章
相關標籤/搜索