webpack进阶构建项目

Posted web前端开发

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了webpack进阶构建项目相关的知识,希望对你有一定的参考价值。

1.理解webpack加载器

webpack的设计理念,所有资源都是“模块”,webpack内部实现了一套资源加载机制,这与Requirejs、Sea.js、Browserify等实现有所不同.

Webpack提供了一套加载器,比如css-loader,less-loader,style-loader,url-loader等,用于将不同的文件加载到js文件中,比如url-loader用于在js中加载png/jpg格式的图片文件,css/style loader用于加载css文件,less-loader加载器是将less编译成css文件;比如代码配置如下:

module.exports = {  entry: "./src/main.js",  output: {    filename: "build.js",    path: __dirname + '/assets/',    publicPath: "/assets/"  },  module: {    loaders: [      {test: /.css$/, loader: 'style!css'},      {test: /.(png|jpg)$/, loader: 'url-loader?limit=8192'}    ]  }  resolve: {    extensions: ['', '.js', '.jsx'],    //模块别名定义,方便后续直接引用别名,无须多写长长的地址    alias: {        a : 'js/assets/a.js',  // 后面直接引用 require(“a”)即可引用到模块
        b : 'js/assets/b.js',        c : 'js/assets/c.js'    }  },  plugins: [commonsPlugin, new ExtractTextPlugin("[name].css")] }


2.html-webpack-plugin学习

首先来看看项目的目录结构如下:

package.json 如下:

{  "name": "html-webpack-plugin",  "version": "1.0.0",  "description": "",  "main": "index.js",  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1"  },  "author": "",  "license": "ISC",  "devDependencies": {    "html-webpack-plugin": "^2.19.0",    "webpack": "^1.13.1"  } }

运行命令 npm install 把依赖包加载出来;

接着在 webpack.config.js配置如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = {    entry: SRC_PATH + "/js/index.js",  //输出的文件名 合并以后的js会命名为index.js  output: {    path: BUILD_PATH,    filename: 'index.js'  },  //添加我们的插件 会自动生成一个html文件  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app'    })  ] };

在项目中的根目录下 运行 webpack 就能生成buid文件夹了,里面会自动生成 两个文件 index.html和index.js文件;
index.html代码如下:

<!DOCTYPE html><html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World app</title>
  </head>
  <body>
  <script type="text/javascript" src="index.js"></script></body></html>

标题title就是我们配置上的;
且合并了依赖的js文件;我们可以直接在本地访问index.html 可以看到能打印出依赖的文件js代码了;可以看到可以解决依赖的问题;
html-webpack-plugin 还支持如下配置:
title: 用于生成的HTML文件的标题。
filename: 用于生成的HTML文件的名称,默认是index.html。你可以在这里指定子目录。
template: 模板文件路径,支持加载器,比如 html!./index.html
inject: true | 'head' | 'body' | false ,注入所有的资源到特定的 template 或者 templateContent 中,如果设置为 true 
或者 body,所有的 javascript 资源将被放置到 body 元素的底部,'head' 将放置到 head 元素中。
favicon: 添加特定的 favicon 路径到输出的 HTML 文件中。
minify:{ //压缩HTML文件
removeComments:true, //移除HTML中的注释
collapseWhitespace:true //删除空白符与换行符
}
hash: true | false, 如果为 true, 将添加一个唯一的 webpack 编译 hash 到所有包含的脚本和 CSS 文件,对于解除 cache 很有用。
cache: true | false,如果为 true, 这是默认值,仅仅在文件修改之后才会发布文件。
showErrors: true | false, 如果为 true, 这是默认值,错误信息会写入到 HTML 页面中
chunks: 允许只添加某些块 (比如,仅仅 unit test 块)
chunksSortMode: 允许控制块在添加到页面之前的排序方式,支持的值:'none' | 'default' | {function}-default:'auto'
excludeChunks: 允许跳过某些块,(比如,跳过单元测试的块)

比如我现在webpack.config.js配置改为如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = {    entry: SRC_PATH + "/js/index.js",  //输出的文件名 合并以后的js会命名为index.js  output: {    path: BUILD_PATH,    filename: 'index.js'  },  //添加我们的插件 会自动生成一个html文件  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: '1.0.0/home.html',      inject: true,      hash: true    })  ] };

然后再在命令行中继续运行webpack命令,可以看到在build下会生成2个目录 第一个是build/1.0.1/home.html; 第二个是 build/index.js
再来看下home.html代码如下:

<!DOCTYPE html><html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World app</title>
  </head>
  <body>
  <script type="text/javascript" src="../index.js?d03211ff5e0251af224d"></script></body></html>

可以看到设置 hash为true js的后缀会自动加一个hash编码,对于页面解决缓存很有用;

生成多个 HTML 文件
通过在配置文件中添加多次这个插件,来生成多个 HTML 文件。
webpack.config.js代码如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = {    entry: SRC_PATH + "/js/index.js",  //输出的文件名 合并以后的js会命名为index.js  output: {    path: BUILD_PATH,    filename: 'index.js'  },  //添加我们的插件 会自动生成一个html文件  plugins: [    new HtmlwebpackPlugin(),    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'app1/home.html',      template: 'src/html/index.html',      inject: true,      hash: true    })  ] };

官网可以看这里 
也可以在配置项 加上minify选项 压缩HTML文件;代码如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = {    entry: SRC_PATH + "/js/index.js",  //输出的文件名 合并以后的js会命名为index.js  output: {    path: BUILD_PATH,    filename: 'index.js'  },  //添加我们的插件 会自动生成一个html文件  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app',      minify:{ //压缩HTML文件
        removeComments:true,    //移除HTML中的注释
        collapseWhitespace:true    //删除空白符与换行符      }    })  ] };

查看html生成后的文件可以看到已经被压缩了;


3.压缩js与css

webpack已经内嵌了uglifyJS来完成对JS与CSS的压缩混淆,无需引用额外的插件。
压缩代码如下:

new webpack.optimize.UglifyJsPlugin({    //压缩代码   compress: {       warnings: false   },   except: ['$super', '$', 'exports', 'require']    //排除关键字})

这里需要注意的是压缩的时候需要排除一些关键字,不能混淆,比如$或者require,如果混淆的话就会影响到代码的正常运行。
webpack.config.js代码改为如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');var webpack = require("webpack");//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); console.log(SRC_PATH) module.exports = {    entry: {    'index' : SRC_PATH + "/js/index.js"  },  //输出的文件名 合并以后的js会命名为index.js  output: {    path: BUILD_PATH + '/js/',    filename: '[name].js'  },  //添加我们的插件 会自动生成一个html文件  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app',      minify:{ //压缩HTML文件
        removeComments:true,    //移除HTML中的注释
        collapseWhitespace:true    //删除空白符与换行符      }    }),    new webpack.optimize.UglifyJsPlugin({    //压缩代码       compress: {           warnings: false       },       except: ['$super', '$', 'exports', 'require']    //排除关键字    })  ] };

继续运行下webpack可以看到js已经被压缩了;注意:但是貌似对es6的语法不能压缩~


4.理解less-loader加载器的使用

 我们先来理解下less-loader加载器,其他的sass-loader也是一个意思,less-loader加载器是把css代码转化到style标签内,

动态插入到head标签内;我们先来看看我项目的结构如下:

webpack进阶构建项目(一)

src/html/index.html代码如下:

<!DOCTYPE html>
 <html>
    <head>
        <meta http-equiv="content-type" content="text/html;charset=utf-8" />
        <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"/>
        <meta content="yes" name="apple-mobile-web-app-capable" />
        <meta content="black" name="apple-mobile-web-app-status-bar-style" />
        <meta content="telephone=no" name="format-detection" />
        <meta content="email=no" name="format-detection" />
        <meta name="description" content="基于webpack的前端工程化开发解决方案探索"/>
        <title>动态生成html的实践</title>
    </head>
    <body>
        <div>hello webpack</div>
    </body></html>

现在我想通过html-webpack-plugin插件动态生成 html页面及引入index.js 和 生成 index.js文件;

webpack.config.js代码配置如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = {  entry: SRC_PATH + "/js/index.js",  output: {    filename: "build.js",    path: BUILD_PATH  },  module: {    loaders: [      //.css 文件使用 style-loader 和 css-loader 来处理      {        test: /\.less$/,        loader: "style!css!less"      }    ]  },  resolve: {    extensions: ['', '.js', '.jsx']  },  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'index.html',      template: 'src/html/index.html',      inject: true,      hash: true    })  ] };

在项目的根目录运行webpack,即可动态生成html文件和js文件,打开生成后的index.html即可看到css生效了,且css被动态内链到head标签内了;

其中less/main.less 文件如下代码:

@color: red;

body {
    background:@color;
}
如上可以看到less文件得到编译,且动态插入到head标签内;


5.理解babel-loader加载器

babel-loader加载器能将ES6的代码转换成ES5代码,我们需要安装babel-loader
执行命令:npm install babel-loader --save-dev 
因此现在需要在webpack.config.js 加入babel-loader的加载器即可;如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = {  entry: SRC_PATH + "/js/index.js",  output: {    filename: "build.js",    path: BUILD_PATH  },  module: {    loaders: [      //.css 文件使用 style-loader 和 css-loader 来处理      {        test: /\.less$/,        loader: "style!css!less"      },      {        test: /\.js$/,        loader: 'babel'      }    ]  },  resolve: {    extensions: ['', '.js', '.jsx']  },  plugins: [    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'index.html',      template: 'src/html/index.html',      inject: true,      hash: true    })  ] };

a.js 假如是ES6的语法;比如如下一句代码:
// es6的语法 
let LOADER = true; 
module.exports = LOADER;

现在在index.js代码如下:
var aModule = require('../less/main.less');
console.log(aModule);

// es6的语法 
var aMoudle = require('./a');
console.log(aMoudle);

可以看到打印 aMoudle的值为true;说明可以正确的解析了;


6.理解 extract-text-webpack-plugin(独立打包样式文件)

执行安装命令:
sudo npm install extract-text-webpack-plugin 
然后再webpack.config.js 加入加载器配置项如下代码:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');var ExtractTextPlugin = require('extract-text-webpack-plugin');//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = {  entry: SRC_PATH + "/js/index.js",  output: {    filename: "build.js",    path: BUILD_PATH  },  module: {    loaders: [      //.css 文件使用 style-loader 和 css-loader 来处理      {        test: /\.less$/,        loader: ExtractTextPlugin.extract(            'css?sourceMap!' +
            'less?sourceMap'        )      },      {        test: /\.js$/,        loader: 'babel'      }    ]  },  resolve: {    extensions: ['', '.js', '.jsx']  },  plugins: [    // 内联css提取到单独的styles的css
    new ExtractTextPlugin("index.css"),    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'index.html',      template: 'src/html/index.html',      inject: true,      hash: true    })  ] };

在项目的根目录运行 webpack 即可生效;会在build目录下 生成 index.css文件,且在打包后的index.html会自动引入link标签的css;
如下所示:

如果页面上有多个less文件或者css文件的话,也可以通过 @import 动态导入;如下在main.less 引入 a.less代码如下:
@import './a.less';
a.less 是和main.less 同级目录下的;


7.webpack打包多个资源文件

 我们在开发页面的时候,有时候需要有多个入口文件,做到文件是按需加载,这样就可以使用缓存提升性能;

只需要像如下编码即可:

module.exports = {  entry: {     "main": "./src/a.js",     "index": "./src/index.js"  },  output: {    filename: "[name].js"  } };

webpack.config.js代码如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');var ExtractTextPlugin = require('extract-text-webpack-plugin');var webpack = require("webpack");//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = {  entry: {     "a": SRC_PATH + "/js/a.js",     "index": SRC_PATH + "/js/index.js",  },  output: {    filename: "[name].js",    path: BUILD_PATH  },  module: {    loaders: [      //.css 文件使用 style-loader 和 css-loader 来处理      {        test: /\.less$/,        loader: ExtractTextPlugin.extract(            'css?sourceMap!' +
            'less?sourceMap'        )      },      {        test: /\.js$/,        loader: 'babel'      }    ]  },  resolve: {    extensions: ['', '.js', '.jsx']  },  plugins: [    // 内联css提取到单独的styles的css
    new ExtractTextPlugin("index.css"),    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'index.html',      template: 'src/html/index.html',      inject: true,      hash: true    }),    new webpack.optimize.UglifyJsPlugin({    //压缩代码       compress: {           warnings: false       },       except: ['$super', '$', 'exports', 'require']    //排除关键字    })  ] };


8.webpack对图片的打包

 图片是 url-loader来加载的,我们既可以在css文件里url的属性;

首先先安装 url-loader插件;
sudo npm install --save-dev url-loader

首先在less文件里面加入如下代码:
@color: red;
body {
background:@color;
background:url('../images/1.png') no-repeat;
}
在index.js里面加入如下代码:
var aModule = require('../less/main.less');
console.log(aModule);

在webpack.config.js代码配置加入如下:
{
test: /.(png|jpg)$/, 
loader: 'url?limit=8192'
}
webpack.config.js所有代码如下:

var path = require('path');var HtmlwebpackPlugin = require('html-webpack-plugin');var ExtractTextPlugin = require('extract-text-webpack-plugin');var webpack = require("webpack");//定义了一些文件夹的路径var ROOT_PATH = path.resolve(__dirname);var SRC_PATH = path.resolve(ROOT_PATH, 'src');var BUILD_PATH = path.resolve(ROOT_PATH, 'build'); module.exports = {    entry: {     "a": SRC_PATH + "/js/a.js",     "index": SRC_PATH + "/js/index.js",  },  output: {    filename: "[name].js",    path: BUILD_PATH  },  module: {    loaders: [      //.css 文件使用 style-loader 和 css-loader 来处理      {        test: /\.less$/,        loader: ExtractTextPlugin.extract(            'css?sourceMap!' +
            'less?sourceMap'        )      },      {        test: /\.js$/,        loader: 'babel'      },      {        test: /.(png|jpg)$/,        loader: 'url?limit=8192&name=img/[hash:8].[name].[ext]'      }    ]  },  resolve: {    extensions: ['', '.js', '.jsx']  },  plugins: [    // 内联css提取到单独的styles的css
    new ExtractTextPlugin("index.css"),    new HtmlwebpackPlugin({      title: 'Hello World app',      filename: 'index.html',      template: 'src/html/index.html',      inject: true,      hash: true    }),    new webpack.optimize.UglifyJsPlugin({    //压缩代码       compress: {           warnings: false       },       except: ['$super', '$', 'exports', 'require']    //排除关键字    })  ] };

因此在项目的根目录运行webpack后,即可,然后会生成index.css文件代码如下:
body{background:red;background:url(8eaebaa98ed1fe64bbf9f0f954b2b230.png) no-repeat}
因此可以看到会动态转换成base64编码;


未完待续~

以上是关于webpack进阶构建项目的主要内容,如果未能解决你的问题,请参考以下文章

进阶|基于webpack的架构与构建优化——YY-DSA搭建心得

如何使用webpack加载库源映射?

webpack入门系列2

webpack进阶用法你都get到了么?

2 webpack 进阶用法

Webpack构建项目进一步优化