前端工具安裝簡述
前言
雖然一直有寫前端,而且水平自認上升很快,但是仍然沒有玩過模塊化開發。
對於前端的這些工具也沒有接觸過,平時一般都是vs和vs code就搞定了,為了搞一搞模塊化開發,准備來玩一下這些前端工具。
所以寫寫這些前端工具的安裝步驟,記錄一下以后忘了也能用,如果能幫到別人就更好了。
1、NPM和Node.js的安裝
安裝node.js后,自動就安裝了npm,所以這里兩者寫到一起了。
nodejs的下載地址:
https://nodejs.org/en/download/
這種東西給個下載地址就好了,根據自己電腦類型安裝,做程序員的也沒有電腦小白,下一步就不說了。
npm下載源的配置
npm在這里被我理解為一個下載工具,而下載的地址為https://www.npmjs.com 。
只不過在國內訪問不穩定,因此建議使用國內鏡向站點https://npm.taobao.org 。
在cmd.exe中,運行以下命令即可:
npm --registry https://registry.npm.taobao.org info underscore
或者找到Nodejs安裝文件夾中的npmrc文件,在該文件中加入
registry = https://registry.npm.taobao.org
2、gulp的安裝
gulp用來優化前端工作流程。
全局安裝gulp:
npm install gulp -g
輸入gulp -v可以查看到相應版本
使用到項目中:
以下是我用vs code自己建的一個項目:
命令行cd到自己建的項目文件夾,然后npm init即可生成自己的package.json,這是自己項目的每個項目的一個描述文件,定義了這個項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數據)。
將gulp安裝到項目中
npm install gulp --save-dev
安裝后:
此時項目中多了node_modules這個文件夾,同時package.json中自動寫入了devDependencies字段,並在該字段下填充了gulp模塊名。
接下來安裝上面gulp中可用的一堆插件
npm install --save-dev gulp-uglify gulp-concat gulp-imagemin gulp-htmlmin gulp-clean-css gulp-rev-append gulp-autoprefixer
安裝后:
gulp-uglify為壓縮js文件,gulp-concat為合並打包文件,gulp-imagemin為壓縮圖片,gulp-htmlmin為壓縮html,gulp-clean-css壓縮css文件,gulp-rev-append為添加版本號。
實際上.NET MVC的bundle繼承了上面這些功能,所以用.net進行開發貌似完全用不到,不過想來別的語言也許應該還是需要的。
而gulp-autoprefixer是根據設置瀏覽器版本自動處理瀏覽器前綴,gulp-less插件將less文件編譯成css,當有less文件發生改變自動編譯less,並保證less語法錯誤或出現異常時能正常工作並提示錯誤信息。
肯定還是有一些別的功能的插件,這只是我暫時了解到的幾個,如果有其它好用的也希望有大神能留言告訴我一下。
編寫gulpfile.js文件
如果要用這些插件,那么還要在根目錄下加一個gulpfile.js配置文件,以下為我自己的測試項目:
根據測試項目寫的配置文件:
/*引入gulp及相關插件 require('node_modules里對應模塊')*/ var gulp = require('gulp'); var minifyCss = require("gulp-clean-css"), uglify = require('gulp-uglify'), concat = require('gulp-concat'), imagemin = require('gulp-imagemin'), htmlmin = require('gulp-htmlmin'), rev = require('gulp-rev-append'), autoprefixer = require('gulp-autoprefixer'), less = require('gulp-less'); //壓縮html,並給頁面的引用添加版本號,清除頁面引用緩存 gulp.task('minifyHtml', function() { var options = { removeComments: true, //清除HTML注釋 collapseWhitespace: true, //壓縮HTML collapseBooleanAttributes: true, //省略布爾屬性的值 <input checked="true"/> ==> <input /> removeEmptyAttributes: true, //刪除所有空格作屬性值 <input id="" /> ==> <input /> removeScriptTypeAttributes: true, //刪除<script>的type="text/javascript" removeStyleLinkTypeAttributes: true, //刪除<style>和<link>的type="text/css" minifyJS: true, //壓縮頁面JS minifyCSS: true //壓縮頁面CSS }; gulp.src('examples/*.html') .pipe(htmlmin(options)) .pipe(rev()) .pipe(gulp.dest('dist/html')); }); //壓縮圖片 gulp.task('minify-img', function() { gulp.src('src/img/*.{png,jpg,gif,ico}') .pipe(imagemin()) .pipe(gulp.dest('dist/img/')); }); //編譯less gulp.task('handleLess', function() { gulp.src('src/less/*.less') .pipe(less()) .pipe(gulp.dest('src/css')); }); //設置瀏覽器版本自動處理瀏覽器前綴,並壓縮css gulp.task('minify-css', function() { gulp.src('src/css/*.css') .pipe(autoprefixer({ browsers: ['last 2 versions', 'Android >= 4.0'], cascade: true, //是否美化屬性值 默認:true 像這樣: //-webkit-transform: rotate(45deg); // transform: rotate(45deg); remove: true //是否去掉不必要的前綴 默認:true })) .pipe(minifyCss()) .pipe(gulp.dest('dist/css/')); }); //打包並壓縮js gulp.task('minify-script', function() { gulp.src('src/js/*.js') .pipe(concat('helloworld.js')) //打包 .pipe(uglify()) //壓縮 .pipe(gulp.dest('dist/js/')); }); gulp.task('default', ['minifyHtml', 'minify-img', 'handleLess', 'minify-css', 'minify-script']);
運行gulp完成前端構建
根據上面的配置我們可以在命令行輸入 :
gulp minify-script
這就只打包壓縮JS文件,也可以輸入:
gulp minify-script
這樣就完成我們所有的構建工作。
進一步的學習可以轉到:http://www.gulpjs.com.cn/
3、webpack的安裝
webpack是一個前端模塊化方案,只不過是本地的,而類似requireJs和sea.js是在線模塊化方案。
有了上面安裝gulp的經驗webpack就簡單多了。
安裝webpack :
npm install webpack -g
接下來增加package.json配置文件,也就是
npm init
只不過我們前面配置了,那么直接下一步:
npm install webpack --save-dev
同樣這個webpack也會加到node_modules文件夾中。
那么來一段簡單的前端示例,使用webpack來實現前端模塊化,我有兩個文件:
hello.js
window.resize = function() { console.info("我resize了!"); }
helloApp.js
var hello = require('./hello.js');
console.log(hello);
雖然不清楚語法,但是大概也能明白,helloApp.js引用了hello.js。
運行
webpack src/js/helloApp.js dist/js/helloApp.Main.js
然后生成的helloApp.Main.js是下面這個樣子:
/******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // identity function for calling harmony imports with the correct context /******/ __webpack_require__.i = function(value) { return value; }; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 1); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports) { window.resize = function() { console.info("我resize了!"); } /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { var hello = __webpack_require__(0); console.log(hello); /***/ }) /******/ ]);
一大段代碼看着就很捉急,不過實際上看看也不過就是個立即執行函數,我刪減了一些代碼,並進行了一些格式化,以下是我的代碼:
(function(modules) { //將我們兩個文件中的代碼作為一個函數對象傳進這里 //然后進行某些處理 }) ( [ ( function(module, exports) { //仔細對照,這是我們被引用的hello.js的代碼 window.resize = function() { console.info("我resize了!"); } } ), ( function(module, exports, __webpack_require__) { //仔細對照,這是我們的helloApp.js的代碼, //只不過require被換位了__webpack_require__ //而里面的路徑'./hello.js'被換位了0,哈,簡單猜想一下,這個0就是我們hello.js的代碼所在的函數對象,在傳進去的moudles數組中所在的索引 var hello = __webpack_require__(0); console.log(hello); } ) ] );
然后我們加入部分被刪掉的代碼:
(function(modules) { // The module cache /******/ var installedModules = {}; /******/ // The require function //(2)第二步看第一步調用的這個函數,果然1就是moduleId /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache // 查看模塊緩存中有不有moduleId為1的,有就直接返回installedModules[moduleId].exports // 讀到這里只知道起到個緩存的作用,先不管這個是什么鬼,下一步 /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) // 走到這里,肯定表示沒緩存嘛,於是創建下面這個對象 // 這個對象的i為入口模塊索引, // l是false,不知道什么鬼不管, // exports就是輸出對象嘛,同時將這個對象的引用交給了installedModules[moduleId]和module // 也就是說這個對象我們緩存了 /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function // 來到了有趣的地方,modules是我們傳進來的模塊數組,modules[moduleId]就是我們的入口函數,也就是下面這個: // ( // function(module, exports, __webpack_require__) { // hello = __webpack_require__(0); // console.log(hello); // } // ) // 那么運行下面代碼的大致效果就是: // var entryModule=function(module, exports, __webpack_require__) { // hello = __webpack_require__(0); // console.log(hello); // }; // entryModule(module,module.exports,__webpack_require__); // 這段代碼的就厲害了,又執行了__webpack_require__這個函數,不過此時的參數為0,也就是我們那個被引用的js的代碼的函數對象的索引 /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded // 此時我們了解到l的作用表示這個模塊是否被加載 /******/ module.l = true; /******/ /******/ // Return the exports of the module // 然后返回 module.exports, // 如果此時是hello.js的代碼運行完,那么此時就會將hello.js中給形參exports的部分返回給hello那個變量 // 此時我就明白了,webpack在不同的js之間如何建立依賴關系 // 讓被引用的部分只返回希望返回的部門,放到exports中,供引用的js調用 /******/ return module.exports; /******/ } /******/ /******/ // Load entry module and return exports // (1)第一步,看上面自帶的注釋,表示:這是載入入口模塊,並且返回輸出 // 這個入口模塊什么的,給了個s什么的,然后給了它個1,這里的s暫時看着沒什么用啊 // 那么就看成__webpack_require__(1)就好了 // 這個1的話我們猜測就是傳進來的module數組中那個引用其他js的helloApp.js的代碼的函數對象的索引 /******/ return __webpack_require__(__webpack_require__.s = 1); }) ( [ ( function(module, exports) { //仔細對照,這是我們被引用的hello.js的代碼 window.resize = function() { console.info("我resize了!"); } } ), ( function(module, exports, __webpack_require__) { //仔細對照,這是我們的helloApp.js的代碼, //只不過require被換位了__webpack_require__ //而里面的路徑'./hello.js'被換位了0,哈,簡單猜想一下,這個0就是我們hello.js的代碼所在的函數對象,在傳進去的moudles數組中所在的索引 hello = __webpack_require__(0); console.log(hello); } ) ] );
OK,到了這里,我對webpack的大致功能就有了一個了解~~~~~。
這不就跟我們在.net或者java中的using或import一樣嘛,而上面這個這個東西就是我們的Main函數,果然,沒什么高大上的,其實就是這么簡單。
接下來就去了解一下webpack的具體配置,首先新建一個webpack.config.js文件,然后讓打包簡單化:
module.exports = { entry: './src/app.js', output: { path: './dist', filename: 'app.bundle.js' } };
然后直接運行webpack命令即可,就相當於自動去找webpack.config.js文件,然后根據文件中的入口app.js去生成app.bundle.js。
到這里意思就很明白了,webpack實際上就是一個類似Seajs、RequireJS一樣的東西。
接下來的工作貌似就是去查webpack的如何去配置什么的了,這種細枝末節的這里就不講了。
貌似這是一個安裝的帖子 ~~~