webpack前端自动化构建方案

2016-09-04  本文已影响0人  油油011

转载请注明原作者以及链接,谢谢!


我们项目的框架使用的是angular.js(v1.5.8)+ webpack,使用webpack主要是要想做到以下几点:
1.抛弃原来项目中的requireJs,gulp/grunt。模块化和打包均由webpack实现。
2.将项目资源大部分输出到一个bundle.js文件,减少浏览器首次加载时的资源请求数量。
3.使用npm安装框架依赖。不再引入项目中。避免项目代码提交时更改库代码。
4.进行代码压缩,并开启nginx的gzip,对代码再次进行压缩。
5.实现测试和生产环境使用不同的配置文件。
6.生成带有项目名称和版本号的文件夹并压缩(用于webApp)。
7.生成带有hash的bundle.js文件。可以解决浏览器因为缓存不刷新的问题(用于web项目)。

因为项目情况,没有用到es6,scss等。没有进行代码转换。如果需要转码,只要找到对应的loader。npm安装后加载进来就可以了,这里不会提到。另外,webpack我也没用多久。如果哪里写的不好或者写错了,请指点,谢谢!
先奉上webpack文档地址:webpack


▍第一步:搭建环境

安装node.js和npm

npm 是 javaScript的包管理工具,类似maven的依赖管理, 用它来下载我们需要的模块。
Node.js下载地址

创建package.json

npm init
在项目文件夹下新建一个package.json并填写项目信息,项目名称以及版本号等项目信息

npm安装插件

全局安装webpack:
npm install webpack -g
安装webpack-dev-server:
npm install webpack-dev-server -g
安装依赖到项目中并加入package.json
npm install [package] --save-dev/ npm install [package] --save
可能有时候会npm安装包比较慢甚至是安装不了,可以使用淘宝NPM镜像[cnpm]
删除依赖
npm uninstall [package]

▍第二步:编写webpack.config.js文件

代码:webpack+anuglar.js
目录结构:
webpack
|____app
| |____index.html
| |____index.js
|____package.json
|____webpack.config.js
|____zip.js
使用loader加载器对资源进行转换
module.exports = {
    entry: path.resolve(__dirname, "app", "index.js"),
    output: {
        path: "dist",
        filename: "bundle.[hash].js"
    },
    module: {
        loaders: [
            {
               test: /\.js$/,
               exclude: /node_modules/,
                loader:"ng-annotate"
            }, {
               test: /\.css$/,
               loader: "style!css!autoprefixer"
            }, {
               test: /\.html$/,  
               exclude: /node_modules/,
               loader:"html"
            }, {
               test: /\.(ttf|eot|otf)$/,
               loader: "file"
            }, {
               test: /\.woff(2)?$/,
               loader: "url?limit=8192&minetype=application/font-woff"
            }, {
               test: /\.(png|jpg|gif|svg)$/,
               loader: "url?limit=8192&name=images/[name].[ext]"
            }
        ]
    }
}
entry编译的入口Js文件。ouput文件输出定义

编译后的文件名bundle.[hash].js,这里用到hash。每一次进行webpack打包,都会生成一个hash值,用它为文件命名,能让每次生成的文件名都不一样。浏览器访问也不会存在缓存问题。path.resolve用来拼接路径,__dirname是指当前路径的绝对路径。

loader加载器的使用,如css-loader。

首先安装css-loader:npm install --save-dev css-loader
在配置文件中,通过正则绑定对应的loader, 可以省略loader,写成css/css-loader均可。使用!可以定义多个loader,?后边配置参数

ng-annotate-loader是用来处理angular.js的代码。这是一小段代码:
angular.module('myApp', [])
       .controller('testCtrl',  function ($scope) {});

$scope普通的压缩会把它当成参数压缩了。解决的方法,一种是写成数组

['$scope', function($scope) {}];
// 或者是
testCtrl.$inject = ['$scope'];

另外一种是使用ng-annotate。编译之后,会自动补全

angular.module('myApp', [])
       .controller('testCtrl',  ["$scope", function ($scope) {}]);
autoprefixer-loader可以补全css代码
图片base64编码

图片这里使用url-loader,会过滤图片。
limit=8192 : 将图片大小小于8K的转为base64编码。
name=images/[name].[ext] : 大于8k的图片则存放到dist/images底下。

webpack sourcemap

调试的时候可能需要知道这个页面对应了哪些文件。这里就要用到sourcemap。可以使用命令webpack -d去生成,或者在webpack.config.js中配置devtool
其实调试很多时候主要还是看样式来自哪个文件。所以这里简单一点,如果是测试环境。css-loader文件后边加上sourcemap。这样子编译的文件小,速度也快一些。我有时候配置devtool不起效果。也不知道为什么。
{ test: /\.css$/, loader: "style!css?sourceMap!autoprefixer" }

生成index.html

每一次生成的bundle.js文件因为带有hash,所以都是不同的。不能在index.html里边直接引入。这里要用到一个插件html-webpack-plugin根据模板生成index.html页面(github地址)。
安装:npm install html-webpack-plugin --save-dev
引入:var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    ...
    plugins: [                                       
        new HtmlWebpackPlugin({        
            filename: path.resolve([输出路径], 'index.html'),
            template: path.resolve([输入路径], "index_template.html")
        })
    ]
}

在模板index_template.html不需要引入bundle.js。生成index.html会自动引入。

▍第三步:编译打包项目工程

webpack常用指令:
$ webpack        // 最基本的启动webpack方法
$ webpack -w     // 提供watch方法,实时进行打包更新
$ webpack -p     // 对打包后的文件进行压缩
$ webpack -d     // 提供source map,方便调试。
环境配置(webpack.config.js)
"scripts": {
  "production": "set NODE_ENV=production && webpack -p",
    "test" : "set NODE_ENV=test && webpack"
}

执行npm run production / npm run test
这是以前的做法。通过设置环境变量NODE_ENV来判断打包的环境。在webpack.config.js中通过process.env.NODE_ENV获取这个值。
发现在mac上是可以的,但在windows底下。scripts中使用&&是有问题的。后来改了一下。直接把webpack -p这个指令当做生产环境。其他视为调试。

获取到指令的第二个参数,为-p则判断为生产环境。
var isProductEnv = process.argv[2] === '-p';

然后可能需要不同环境配置一些变量。比如说HTTP请求的地址。因为这些都属于项目的内容。就不想在webpack.config.js中配置。直接配置到app文件夹中。在项目中判断当前环境,require对应的JSON数据。

// webpack.config.js
var DefinePlugin = require('webpack').DefinePlugin;
var definePlugins = new DefinePlugin({
    webpack_prod : isProductEnv
});
module.exports = {
    ...
    plugins: [                                       
        definePlugins,
        ...
    ]
}
// index.js
if (webpack_prod) {
    require('./env/product');
} else {
    require('./env/test');
}
webpack-dev-server本地webserver

启动:webpack-dev-server
地址:http://localhost:port/webpack-dev-server/dist/index.html
文档地址 :webpack-dev-server文档
端口号默认是8080,可以在devServer中更改。每次改代码保存后,会自动编译并且刷新页面。还可以做到热替换即不刷新页面可以更新。除此之外还有一个proxy功能可以用来配置代理。

压缩成项目名称_版本号.zip

使用node.js的插件zip-local
安装并加入项目中:
npm install zip-local --save-dev
项目目录下建立zip.js文件

// 从package.json文件中获取到项目名称和版本号
var packageInfo = require('./package.json');
var zip = packageInfo.name + "_" + packageInfo.version;
// 引入插件
var zipper = require('zip-local');
// 压缩dist文件夹
zipper.sync.zip("dist/").compress().save(zip + ".zip");

执行命令行 node zip 生成zip压缩文件。

▍第四步:开启nginx的gzip功能

webpack打包编译后成一个文件,文件会比按需加载大。web项目在第一次加载的时候,文件太大的话会比较慢。所以要想办法把它的体积变小再变小。

未压缩前,执行命令webpack

![](https://github.com/n98745/MarkdownPhotos/blob/master/webpack/3D5D26AE-AD6E-464E-8AB6-04490118096A.png?raw=true =100x100)

先使用webpack自带的压缩,执行命令webpack -p

![](https://github.com/n98745/MarkdownPhotos/blob/master/webpack/20E389BE-0ABB-405D-8DD4-08B94D599BD1.png?raw=true =100x100)

开启nginx的gzip功能

官方文档:Module ngx_http_gzip_module
翻译:Nginx官方文档翻译--ngx_http_gzip_module模块

gzip on;
gzip_proxied any;
gzip_disable "msie6";
gzip_comp_level 3;
gzip_min_length 4k;
gzip_types text/css text/xml application/javascript;
开启后:

![](https://github.com/n98745/MarkdownPhotos/blob/master/webpack/5C448E36-480C-4071-8240-33BC35A48896.png?raw=true =100x100)
这样子就把我们刚刚接近2M的项目代码压缩到150Kb。

▍webpack模块化

webpack支持CommonJs和AMD规范。前者是同步加载,后者是异步加载。webpack加载的对象是module。它把静态资源都当做是模块。不仅仅只是js。还有css、html、图片等等都可以通过require去引入,如引入图片:

var img = document.createElement("img");
img.src = require("../image/xxx.jpg");
document.body.appendChild(img);

模块输出:module.exports = ...

webpack resolve

这个是在webpack.config.js中去配置的一个对象。它的几个用法:

1. extensions
// 当后缀名为空的时候,会自动识别并不缺
resolve: { 
       extensions: ['', '.js'] 
}  
2. alias
// 通过别名可以减少打包时间,项目中直接require("consts")重定向到指定的文件。
resolve: { 
      alias: { 
          consts: path.resolve(__dirname, "app/util/constant.js")
      } 
} 
全局引入

有时候像jquery想要给它配置全局,使用$去引入。
首先安装依赖到项目中
npm install --save-dev jquery
配置plugins,然后就可以在项目中使用。

plugins:[
    new webpack.ProvidePlugin({
        $:"jquery"
    })
]
引入依赖

项目中要用到angular,npm install --save-dev angular把依赖下载到文件夹node_modules中。
通过require("angular")可以直接引入

上一篇下一篇

猜你喜欢

热点阅读