Gulp學(xué)習(xí)

參照Gulp for Beginners來學(xué)習(xí)Gulp基本內(nèi)容。以下為學(xué)習(xí)記錄筆記。

安裝Gulp

首先需要安裝Node.js,并在控制臺(tái)輸入$ npm install gulp -gMac端需要寫成$ sudo npm install gulp -g(因?yàn)镸ac端需要在管理員下)運(yùn)行來安裝Gulp,-g表示全局安裝。

創(chuàng)建一個(gè)Gulp項(xiàng)目

學(xué)習(xí)過程,將使用一個(gè)名為project的文件夾作為項(xiàng)目根目錄,在文件夾內(nèi)運(yùn)行$ npm init,這將會(huì)為你的項(xiàng)目創(chuàng)建一個(gè)叫package.json的文件,文件會(huì)存儲(chǔ)關(guān)于你的項(xiàng)目的信息,就像在項(xiàng)目里使用的依賴(Gulp就是依賴的一個(gè)例子)
在創(chuàng)建了package.json之后,就可以通過$ npm install gulp --save-dev在項(xiàng)目中安裝Gulp,這次我們是把Gulp安裝到project項(xiàng)目中,而不是全局安裝。(這次Mac端也不需要使用sudo)--save-dev意思是把gulp作為依賴添加到當(dāng)前項(xiàng)目。
現(xiàn)在,可以在原來的文件夾中看到一個(gè)node_modules文件夾,在node_modules文件夾中包含著gulp文件夾。

已經(jīng)做好使用Gulp的準(zhǔn)備工作,在我們使用Gulp之前我們必須清楚我們將要怎么在項(xiàng)目中使用Gulp,其中之一就是決定目錄結(jié)構(gòu)。

確定文件結(jié)構(gòu)

一般webapp文件結(jié)構(gòu)

在這個(gè)結(jié)構(gòu)中,app文件夾是用來做開發(fā)的,dist文件夾是用來包含生產(chǎn)現(xiàn)場(chǎng)的優(yōu)化文件。
因?yàn)?code>app是用于開發(fā),所以我們所有的代碼都會(huì)放在app文件夾下。
在配置Gulp時(shí),我們必須記住文件夾的結(jié)構(gòu)。現(xiàn)在就可以開始在存儲(chǔ)所有Gulp配置的gulpfile.js創(chuàng)建第一個(gè)Gulp任務(wù)。

寫你的第一個(gè)Gulp任務(wù)

使用Gulp的第一步是把它require到gulpfile中

var gulp=require('gulp');

這個(gè)require語(yǔ)句會(huì)告訴Node在node_modules文件夾中查找一個(gè)叫gulp的包,一旦找到,就會(huì)把包的內(nèi)容賦值到變量gulp中。
接下來就可以使用這個(gè)gulp變量來寫gulp任務(wù),一個(gè)gulp任務(wù)的基礎(chǔ)語(yǔ)法是:

gulp.task('task-name',function(){
    //stuff here
});

task-name指的是任務(wù)的名字,將會(huì)被用在你想在Gulp運(yùn)行一個(gè)任務(wù)的時(shí)候。你也可以使用命令行gulp task-name來運(yùn)行相同的任務(wù)。

測(cè)試?yán)樱?/p>

var gulp=require('gulp');
gulp.task('hello',function(){
    console.log('Hello world!');
});

我們可以通過在控制臺(tái)輸入$ gulp hello來運(yùn)行這個(gè)任務(wù)。
就可以在控制臺(tái)看到以下的結(jié)果:


Gulp任務(wù)通常會(huì)比這個(gè)復(fù)雜,通常會(huì)包含兩個(gè)額外的Gulp方法,和各種Gulp插件。
以下是一個(gè)真實(shí)任務(wù)可能的情況:

gulp.task('task-name', function () { 
return  gulp.src('source-files') // Get source files withgulp.src 
.pipe(aGulpPlugin()) // Sends it through a gulp plugin 
.pipe(gulp.dest('destination')) // Outputs the file in the destination folder
})

可以看到,一個(gè)真實(shí)的任務(wù)會(huì)用到兩個(gè)額外的gulp方法——gulp.srcgulp.dest
gulp.src告訴Gulp 任務(wù)在這個(gè)任務(wù)中使用哪些文件。gulp.dest告訴Gulp當(dāng)任務(wù)完成時(shí)應(yīng)該在哪里輸出。

用Gulp預(yù)處理

使用一個(gè)叫gulp-sass的插件可以在Gulp將Sass編譯成CSS,使用像安裝Gulp一樣的npm install命令安裝gulp-sass到項(xiàng)目中:

$ npm install gulp-sass --save-dev

使用--save-dev標(biāo)記來保證gulp-sass被添加到package.json中的devDependencies中。

PS:在下載插件的過程中可能會(huì)遇到下載較慢的問題,可通過調(diào)用國(guó)內(nèi)鏡像來解決 來源
鏡像使用方法(三種辦法任意一種都能解決問題,建議使用第三種,將配置寫死,下次用的時(shí)候配置還在):
1.通過config命令
npm config set registry https://registry.npm.taobao.org npm info underscore (如果上面配置正確這個(gè)命令會(huì)有字符串response)
2.命令行指定
npm --registry https://registry.npm.taobao.org info underscore
3.編輯~/.npmrc
加入下面內(nèi)容
registry = https://registry.npm.taobao.org
搜索鏡像: https://npm.taobao.org
建立或使用鏡像,參考: https://github.com/cnpm/cnpmjs.org

在安裝過程中我自己還遇到另一個(gè)問題,錯(cuò)誤信息

gyp verb check python checking for Python executable "python2" in the PATH
gyp verb `which` failed Error: not found: python2

解決辦法: $ npm install python

在我們使用這個(gè)插件之前,我們必須像使用gulp那樣先把gulp-sassnode_modules文件夾中require進(jìn)來。

var gulp = require('gulp');
// Requires the gulp-sass pluginvar 
sass = require('gulp-sass');

現(xiàn)在就可以把上面的aGulpPlugin()替換成sass()

gulp.task('sass', function(){ 
    return gulp.src('source-files') 
   .pipe(sass()) // Using gulp-sass    
   .pipe(gulp.dest('destination'))
});

現(xiàn)在我們需要為sass任務(wù)提供源文件和目標(biāo)文件來使得任務(wù)運(yùn)行,現(xiàn)在在app/scss創(chuàng)建一個(gè)styles.scss文件。這個(gè)文件將會(huì)在gulp.src()中被添加到sass任務(wù)。
這里我們把最終的styles.css文件輸出到app/css文件夾中,這將是gulp.destdestination

gulp.task('sass', function(){
    return gulp.src('app/scss/styles.scss') 
    .pipe(sass()) // Converts Sass to CSS with gulp-sass 
    .pipe(gulp.dest('app/css'))
});

為了測(cè)試sass任務(wù)是否像我們希望的那樣運(yùn)行。我們會(huì)在styles.scss中添加一個(gè)Sass方法。

// styles.scss
.testing { width: percentage(5/7);}

在控制臺(tái)上運(yùn)行gulp sass后,回到app/css目錄下,可以看到一個(gè)styles.css的文件。內(nèi)容如下:

.testing {
  width: 71.42857%; }

PS:Gulp-sass使用LibSass把Sass轉(zhuǎn)換成CSS,這會(huì)比基于Ruby的方法更快。如果你想依然在gulp中使用Ruby方法的話,可以使用gulp-ruby-sass或者gulp-compass.

Node中的通配符(Globbing in Node)

Globs(通配符)是允許你添加多于一個(gè)文件進(jìn)gulp.src()中的匹配模式。這就像是普通的表達(dá)式,但是是專門給文件路徑的。
當(dāng)你使用一個(gè)glob的時(shí)候,電腦會(huì)根據(jù)特定的模式來檢查你的文件名稱和路徑。若存在,則該文件就被匹配。
多數(shù)Gulp工作流通常只需要4種不同的通配符模式:

  • ** *.scss: ***是一個(gè)在當(dāng)前目錄匹配所有模式的通配符。在這個(gè)栗子中,我們會(huì)匹配在根目錄(project)下所有以.scss結(jié)尾的文件。
  • ******/*.scss :這是一個(gè)*模式更為極端的一個(gè)版本,它會(huì)匹配根目錄和其它子目錄的所有以.scss結(jié)尾的文件。
  • !not-me.scss:!表明Gulp會(huì)排除掉與之匹配的模式,這在你需要排除掉一個(gè)匹配中的文件時(shí)會(huì)很有用。在這個(gè)栗子中,not-me.scss將會(huì)在匹配中被排除。
  • ** .+(scss|sass) :*加號(hào)和括號(hào)(parentheses)允許Gulp去匹配多種模式,不同的模式被|(pipe)隔開。這個(gè)栗子中,Gulp會(huì)匹配根目錄下所有以.scss.sass結(jié)尾的所有文件。
    現(xiàn)在我們就可以把app/scss/styles.scss替換成scss/**/*.scss模式。
gulp.task('sass', function() { 
    return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss and children dirs 
   .pipe(sass()) 
   .pipe(gulp.dest('app/css'))
})

現(xiàn)在的問題是,我們每次都要手動(dòng)去調(diào)用gulp sass才能把Sass轉(zhuǎn)換成CSS嗎?

我們可以通過一個(gè)叫"watching"的進(jìn)程讓Gulp在sass保存的時(shí)候自動(dòng)運(yùn)行sass任務(wù)。

監(jiān)視Sass文件的變化(Watching Sass files for changes)

Gulp為我們提供了一個(gè)watch方法來檢查文件是否被保存。watch方法的語(yǔ)法是:

// Gulp watch syntax
gulp.watch('files-to-watch', ['tasks', 'to', 'run']); 

如果我們想監(jiān)聽所有的Sass文件并在Sass文件被保存時(shí)運(yùn)行sass任務(wù),我們只需要把files-to-watch換成app/scss/**/*.scss,把['tasks', 'to', 'run']換成['sass']:

// Gulp watch syntax
gulp.watch('app/scss/**/*.scss', ['sass']); 
gulp.task('watch', function(){ 
    gulp.watch('app/scss/**/*.scss', ['sass']); 
    // Other watchers
})

當(dāng)你運(yùn)行了gulp watch命令后,你就能看到Gulp馬上開始監(jiān)聽了。

修改Sass文件
修改Sass文件

接下來就看看怎么讓Gulp在Browser Sync的幫助下實(shí)現(xiàn)在保存一個(gè).scss文件時(shí)重載瀏覽器。

Browser Sync實(shí)時(shí)重載(Live-reloading with Browser Sync)

通過spinning up web 服務(wù)器Browser Sync能讓我們更容易實(shí)現(xiàn)實(shí)時(shí)重載。它也有其它特征,例如多設(shè)備同步動(dòng)作。

  • 第一步:安裝Browser Sync
$ npm install browser-sync --save-dev

你會(huì)發(fā)現(xiàn)當(dāng)我們安裝Browser Sync時(shí)并沒有gulp-前綴。這是因?yàn)锽rowser Sync是和Gulp一起運(yùn)行的,所以我們不需要使用插件。

  • 第二步:require Browser Sync
var browserSync = require('browser-sync').create();

我們需要?jiǎng)?chuàng)建一個(gè)browserSync任務(wù)使得Gulp可以使用Browser Sync旋轉(zhuǎn)加速服務(wù)器。因?yàn)槲覀冋谶\(yùn)行服務(wù)器,我們需要讓Browser Sync知道服務(wù)器的根目錄應(yīng)該在哪里。在這里的栗子中是app 文件夾:

gulp.task('browserSync', function() { 
browserSync.init({ 
    server: {
         baseDir: 'app' 
        },
    })
})
  • 第三步:同時(shí)我們需要對(duì)我們的sass任務(wù)做一點(diǎn)小小的改變,使得Browser Sync可以在sass任務(wù)完成時(shí)向?yàn)g覽器注入新的CSS樣式(更新CSS)。
gulp.task('sass', function() { 
return gulp.src('app/scss/**/*.scss') // Gets all files ending with .scss in app/scss 
    .pipe(sass()) 
    .pipe(gulp.dest('app/css'))   
    .pipe(browserSync.reload({ 
        stream: true 
    }))
});

到這里,我們就配置好Browser Sync了。現(xiàn)在我們需要同時(shí)運(yùn)行watchbrowserSync任務(wù)來做到實(shí)時(shí)重載。
如果我們要打開兩個(gè)命令行窗口來分別運(yùn)行gulp browserSyncgulp watch這會(huì)十分笨重,所以我們要讓Gulp同時(shí)運(yùn)行它們,通過告訴watch任務(wù)browserSync必須在watch運(yùn)行前完成。
可以通過給watch任務(wù)添加第二個(gè)參數(shù)來實(shí)現(xiàn)上述要求。

gulp.task('watch', ['array', 'of', 'tasks', 'to', 'complete','before', 'watch'], function (){ 
    // ...
})

在這個(gè)栗子中,我們會(huì)添加browerSync任務(wù)。

gulp.task('watch', ['browserSync'], function (){   
    gulp.watch('app/scss/**/*.scss', ['sass']); 
    // Other watchers
})

同時(shí),我們也要保證sasswatch前運(yùn)行,以保證CSS在我們運(yùn)行Gulp命令時(shí)都是最新的。

gulp.task('watch', ['browserSync', 'sass'], function (){ 
    gulp.watch('app/scss/**/*.scss', ['sass']); 
    // Other watchers
});

現(xiàn)在,當(dāng)在命令行運(yùn)行了gulp watch,Gulp會(huì)馬上啟動(dòng)sass和'browserSync'。當(dāng)兩個(gè)任務(wù)都完成時(shí),watch才會(huì)運(yùn)行。同時(shí)會(huì)打開app/index.html

如果你改變了styles.scss文件,你會(huì)看到瀏覽器自動(dòng)的重載。

既然我們已經(jīng)監(jiān)視了.scss文件重載,接下來我們看看怎么在HTML或JS文件被保存的時(shí)候重載瀏覽器。
可以通過添加兩個(gè)監(jiān)聽程序,并在文件被保存的時(shí)候調(diào)用browserSync.reload方法。

gulp.task('watch', ['browserSync', 'sass'], function (){ 
    gulp.watch('app/scss/**/*.scss', ['sass']);
    // Reloads the browser whenever HTML or JS files change 
    gulp.watch('app/*.html', browserSync.reload); 
    gulp.watch('app/js/**/*.js', browserSync.reload); });

目前我們已經(jīng)解決了三件事情:

  • 為開發(fā)旋轉(zhuǎn)加速web服務(wù)器
  • 使用Sass預(yù)處理器
  • 在文件被保存時(shí)重載瀏覽器

接下來會(huì)處理優(yōu)化資源的部分。首先沖優(yōu)化CSS和JS文件開始。

優(yōu)化CSS和JS文件

在為產(chǎn)品優(yōu)化CSS和JS文件的時(shí)候,開發(fā)人員通常有兩個(gè)任務(wù)要完成:縮小(minification)和串聯(lián)(concatenation)。

  • 其中一個(gè)開發(fā)人員面臨的問題就是,在使程序自動(dòng)化的時(shí)候很難把你的腳本按正確的順序串聯(lián)。

假設(shè)index.html中包含3個(gè)<script>標(biāo)簽

<body> 
    <!-- other stuff -->
    <script src="js/lib/a-library.js"></script> 
    <script src="js/lib/another-library.js"></script>   
    <script src="js/main.js"></script>
</body>

這些腳本被保存在兩個(gè)不同的目錄。使用傳統(tǒng)的像gulp-concatenate這樣的傳統(tǒng)插件很難做到把他們串聯(lián)在一起。
慶幸的是,gulp-useref可以解決這個(gè)問題。
Gulp-useref通過尋找一個(gè)以開始,以結(jié)尾的注釋來做到把任意數(shù)目的CSS和JS文件串聯(lián)到一個(gè)文件中。

<!-- build:<type> <path> -->
... HTML Markup, list of script / link tags.
<!-- endbuild -->

<type>可以是js,css或者是remove。最好給你想要串聯(lián)的文件的類型設(shè)定type。如果你給設(shè)定remove設(shè)定了type,那么Gulp會(huì)移除整個(gè)build塊而不創(chuàng)建一個(gè)文件。
<path>在這里指的是生成文件的目標(biāo)路徑。

這里我們希望最終的JS文件被生成到j(luò)s文件夾,像main.min.js

<!--build:js js/main.min.js -->
<script src="js/lib/a-library.js"></script>
<script src="js/lib/another-library.js"></script>
<script src="js/main.js"></script>
<!-- endbuild -->

現(xiàn)在配置gulp-useref插件到gulpfile。我們需要安裝并把它require到gulpfile。

$ npm install gulp-useref --save-dev
var useref = require('gulp-useref');

構(gòu)建useref任務(wù)的步驟和其它相似。

gulp.task('useref', function(){ 
    return gulp.src('app/*.html') 
   .pipe(useref()) 
   .pipe(gulp.dest('dist'))
});

運(yùn)行gulp useref就可以了。
然而,文件現(xiàn)在還沒有被縮小。我們需要使用gulp-uglify插件來縮小JS文件。同時(shí),我們還需要另一個(gè)叫gulp-if插件來保證我們只會(huì)縮小JS文件。

// Other requires...
var uglify = require('gulp-uglify');
var gulpIf = require('gulp-if');
gulp.task('useref', function(){ 
    return gulp.src('app/*.html')
    .pipe(useref()) // Minifies only if it's a JavaScript file 
    .pipe(gulpIf('*.js', uglify())) 
    .pipe(gulp.dest('dist'))
});

其它的同理。
在串聯(lián)CSS文件的時(shí)候,使用gulp-cssnano來壓縮文件。

var cssnano = require('gulp-cssnano');
gulp.task('useref', function(){ 
    return gulp.src('app/*.html') 
    .pipe(useref()) 
    .pipe(gulpIf('*.js', uglify())) // Minifies only if it's a CSS file 
    .pipe(gulpIf('*.css', cssnano())) 
    .pipe(gulp.dest('dist'))
});

優(yōu)化圖片

使用gulp-imagemin來優(yōu)化圖片。
通過gulp-imagemin我們可以壓縮png,jpg,gif甚至svg

gulp.task('images', function(){ 
    return gulp.src('app/images/**/*.+(png|jpg|gif|svg)') 
    .pipe(imagemin()) 
    .pipe(gulp.dest('dist/images'))
});

因?yàn)椴煌奈募愋投紩?huì)被不同程度的優(yōu)化,你可能會(huì)想給imagemin增加可選參數(shù)來定制每個(gè)文件的優(yōu)化方式。
例如,你可以通過設(shè)置interlaced參數(shù)為true來創(chuàng)建隔行的GIFs。

gulp.task('images', function(){ 
    return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)') 
    .pipe(imagemin({ 
        // Setting interlaced to true 
       interlaced: true 
    })) 
    .pipe(gulp.dest('dist/images'))
});

優(yōu)化圖片是一項(xiàng)十分慢的過程,除非必須,否則你不會(huì)想要重復(fù)一遍。這樣我們可以使用gulp-cache插件。

var cache = require('gulp-cache');
gulp.task('images', function(){ 
    return gulp.src('app/images/**/*.+(png|jpg|jpeg|gif|svg)') 
   // Caching images that ran through imagemin 
    .pipe(cache(imagemin({
         interlaced: true 
    }))) 
    .pipe(gulp.dest('dist/images'))
});

現(xiàn)在還有一個(gè)需要從app目錄轉(zhuǎn)換到dist目錄,就是fonts 目錄。

復(fù)制fonts到Dist

因?yàn)閒ont文件已經(jīng)被優(yōu)化過了,所以我們不需要再做什么。只需要把fonts復(fù)制到dist就好了。
我們可以通過指明gulp.srcgulp.dest來復(fù)制文件,不需要其它插件。

gulp.task('fonts', function() { 
    return gulp.src('app/fonts/**/*') 
    .pipe(gulp.dest('dist/fonts'))
})

這樣子,當(dāng)你運(yùn)行gulp fonts時(shí),Gulp就會(huì)從app復(fù)制fontsdist

到現(xiàn)在,我們已經(jīng)有了6個(gè)不同的任務(wù),每個(gè)都要在命令行單獨(dú)調(diào)用,這真是一件很笨重的事。因此我們想要把所有命令綁定到一句命令中。

在我們那樣做之前,我們先來看看怎么自動(dòng)清理產(chǎn)生的文件。

自動(dòng)清理產(chǎn)生的文件

我們已經(jīng)可以自動(dòng)創(chuàng)建文件,我們想要確保那些不會(huì)再使用的文件不會(huì)留再任何我們不知道的地方。
這個(gè)過程叫做cleaning(或刪除文件)。

我們使用del來清理文件。
引用方式同上述的其它一樣。

npm install del --save-dev
var del = require('del');

del方法需要在一個(gè)告訴它要?jiǎng)h除哪個(gè)文件的node通配符數(shù)組。
配置一個(gè)Gulp任務(wù)就跟第一個(gè)'hello'任務(wù)差不多。

gulp.task('clean:dist', function() { 
    return del.sync('dist');
})

這樣,當(dāng)你運(yùn)行g(shù)ulp clean:dist時(shí),'dist'文件夾就會(huì)被刪除。

我們不需要擔(dān)心會(huì)刪除了dist/images文件夾,因?yàn)?code>gulp-cache已經(jīng)把圖片緩存在本地系統(tǒng)中了。要想清楚本地系統(tǒng)緩存,你可以單獨(dú)創(chuàng)建一個(gè)叫cache:clear的任務(wù)。

gulp.task('cache:clear', function (callback) {
     return cache.clearAll(callback)
})

結(jié)合Gulp任務(wù)

先來總結(jié)下我們做過的東西,目前,我們已經(jīng)創(chuàng)建了兩類Gulp任務(wù)。
第一種是用于開發(fā)過程的,把Sass編譯成CSS,監(jiān)視變化,有依據(jù)地重載瀏覽器。

第二種適用于優(yōu)化過程的,為產(chǎn)品網(wǎng)站準(zhǔn)備好所有文件。優(yōu)化這個(gè)過程中像CSS,JS和圖片這樣子的資源,把fonts從app復(fù)制到dist

我們之前已經(jīng)用gulp watch命令把第一種任務(wù)組合到一個(gè)工作流中。

gulp.task('watch', ['browserSync', 'sass'], function (){ 
    // ... watchers
})

第二類包括那些我們運(yùn)行來創(chuàng)造產(chǎn)品網(wǎng)站的任務(wù)。其中包括了clean:dist,sass,useref,imagesfonts.
我們需要一個(gè)額外的叫Run Sequence的插件。

$ npm install run-sequence --save-dev

語(yǔ)法:

var runSequence = require('run-sequence');
gulp.task('task-name', function(callback) { 
    runSequence('task-one', 'task-two', 'task-three', callback);
});

這樣任務(wù)就會(huì)一個(gè)接一個(gè)的運(yùn)行。

Run Sequence也允許你同時(shí)運(yùn)行任務(wù),只要你把他們放到一個(gè)數(shù)組中。

gulp.task('task-name', function(callback) { 
    runSequence('task-one', ['tasks','two','run','in','parallel'], 'task-three', callback);
});

為了一致性,我們也可以用相同的序列處理第一組任務(wù)。并且使用default作為任務(wù)名字。應(yīng)為這樣我們?cè)谡{(diào)用的時(shí)候只需要寫gulp

作者的一些建議:
For development:
Using Autoprefixer to write vendor-free CSS code
Adding Sourcemaps for easier debugging
Creating Sprites with sprity
Compiling only files that have changed with gulp-changed
Writing ES6 with Babel or Traceur
Modularizing Javascript files with Browserify, webpack, or jspm
Modularizing HTML with template engines like Handlebars or Swig
Splitting the gulpfile into smaller files with require-dir
Generating a Modernizr script automatically with gulp-modernizr

For optimization:
Removing unused CSS with unCSS
Further optimizing CSS with CSSO
Generating inline CSS for performance with Critical

總結(jié):

這篇文章的內(nèi)容可以幫助我們快速的了解Gulp,但是其中還有很多問題需要深究,還要繼續(xù)學(xué)習(xí)。

PS:評(píng)論區(qū)里有人提到不應(yīng)該使用sudo。
相關(guān)閱讀:
https://pawelgrzybek.com/fix-priviliges-and-never-again-use-sudo-with-npm/
https://github.com/brock/node-reinstall

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容