webpack配置

文章中以 $ 符号开头的是在终端输入的命令 
文章中以 vim 开头为编辑文件内容

从零开始

$ mkdir dailypaper
新建一个项目文件夹dailypaper
$ npm init
    在该文件夹下npm init初始化项目文件夹会产生package.json文件
$ npm install -D webpack    
    本地局域安装webpack依赖
$ npm install -D webpack-dev-server   
     开发环境安装服务器热更新依赖
$ mkdir app        
    创建app文件夹用来存放放原始代码文件
$ mkdir public      
     创建public文件夹用来存放打包后的文件
$ touch webpack.config.js    
    创建web pack.config.js 配置文件

webpack.config.js配置文件四大重要组成部分:入口文件、出口文件、loader、插件plugins

vim web pack.config.js 初始化webpack.config.js的内容

var config = {

};
module.exports = config;

这里的module.exports = config;相当于export default config;。由于目前还没有安装支持ES6的编译插件,因此不能直接用ES6的语法,否则会报错。

vim package.json 的scripts里添加快速启动热更新服务的脚本

{
    //…
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --open --config webpack.config.js",
    },
    //…
}

当运行 npm run dev时,就会执行”webpack-dev-server –open –config webpack.config.js”命令,其中—config 是指向 webpack-dev-server 读取的配置文件路径,即之前创建的 webpack.config.js 文件。—open会在执行命令时自动在浏览器打开页面,默认地址为127.0.0.1:8080,不过IP和端口都是可以配置的,如:

vim package.json

 "scripts": {
    "dev": "webpack-dev-server —-host 172.172.172.1 —-port 8888 —-open --config webpack.config.js",
    },

一般在局域网中,需要其他同事访问时可以这样设置,否则默认就可以

入口出口配置

Webpack配置 最重要的是两项配置入口(Entry)和出口(Output),在dailypaper文件夹下新建一个空的app.js作为入口的文件,再进行

在dailypaper文件下

$ touch app.js
    新建app.js文件   

vim web pack.config.js中

var path = require('path');
var config = {
    entry: {
        app: './app.js'
    },
    output: {
        path: path.join(__dirname,'./public'),
        publicPath: '/public/',
        filename: 'main.js',
    },

};
module.exports = config;

entry中的main是单入口,webpack会从main.js文件开始工作, output中path选项用来存放打包后的文件输出目录,是必填项。 publicPath指定资源文件引用的目录,如果你的资源文件放在CDN上,可填CDN的网址。filename用于指定输出文件的名称。因此,这里配置的output意为打包后的文件会存储为daily/public/main.js文件,只要在html中引入它就可以了。

在dailypaper文件下

$ touch index.html
    新建index.html文件
  • vim index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>dailypaper</title>
</head>
<body>
    <div id="app">
        Hello World
    </div>
    <script src="./public/main.js"></script>
</body>
</html>

然后就可以执行以下命令了:

$ npm run dev    
    就能打开网页显示Hello World了

vim app.js 打开dailypaper文件夹下的app.js,添加一行代码

document.getElementById('app').innerHTML = 'Hello webpack.';

此时页面已经自动变成了Hello webpack. 
此时看浏览器开发者工具的network视图中(刷新页面)的main.js有几千行代码,这是在开发环境下,大多都是webpack-dev-server的功能,只在开发时有效,在生产环境下编译就不会这么臃肿,执行以下命令打包

$ webpack —progress —hide-modules    打包 没有压缩

这时public 下的main.js就只有几十行

loader配置

webpack配置除了入口和出口,需要进一步配置来实现更强大的功能 
每个文件都是一个模块,不同的模块需要不同的加载器loaders来处理,加载器是webpack最重要的功能,通过安装不同的加载器可以对各种后缀名的文件进行处理,比如CSS样式需要用到 style-loaderloader和 css-loader

$ install css-loader style-loader -D
安装完成后再在webpack.config.js中配置Loader,增加对css文件的处理

vim web pack.config.js

var path = require('path');
var config = {
    entry: {
        app: './app'
    },
    output: {
        path: path.join(__dirname,'./public'),
        publicPath: '/public/',
        filename: 'main.js'
    },
    module: {
        rules: [
            {
                test:/\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            }
        ]
    }

};

module.exports = config;

在 module 对象中的 rules 属性中可以指定一系列的 loaders ,每一个 loader 必须包含 test 和 use 两个选项, 
以上意思是,当遇到后缀名为.css的文件时,先将它通过 css-loader 转换,再通过 style-loader 转换,然后继续打包,use的值可以是字符串或者数组,如果是数组,它的编译顺序是从后往前。

dailypaper文件夹下

$ touch style.css
    新建style.css,并在app.js中导入

vim style.css

#app {
    font-size:24px;
    color:#f50;
}

vim 在app.js中

import './style.css’;    //配置了loader之后,就可以直接这么将样式文件通过import引入js 文件中
document.getElementById('app').innerHTML = 'Hello webpack.';

插件配置

CSS是通过JS动态创建 style 标签来写入的, 这意味着代码已经编译在了main.js中,但在实际业务中,样式文件会很多,都放在JS里太占体积,还不能做缓存。这时候需要用到另一个重要——插件(Plugin) 
这里可以使用一个 extract-text-webpack-plugin 的插件来将散落在各地的CSS提取出来,并生成一个main.css文件,最终在index.html里通过 的形式加载。

$ npm install extract-text-webpack-plugin -D

然后在配置文件中导入插件,并改写loader的配置

vim web pack.config.js

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
    entry: {
        app: './app'
    },
    output: {
        path: path.join(__dirname,'./public'),
        publicPath: '/public/',
        filename: 'main.js'
    },
    module: {
        rules: [
            {
                test:/\.css$/,
                // use: [
                //     'style-loader',
                //     'css-loader'
                // ]
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',
                    fallback:'style-loader'
                })
            }
        ]
    },
    plugins:[
        //重命名提取后的CSS文件,此时必须要在index.html中引用才会有样式效果,打包成一个main.css
        new ExtractTextPlugin("main.css")
    ]

};

module.exports = config;

vim Index.html 必须要使用 link 标签来引用才会有样式展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>dailypaper</title>
    <link rel="stylesheet" type="text-css" href="/public/main.css">
</head>
<body>
    <div id="app">
        Hello World
    </div>
    <script src="/public/main.js"></script>
</body>
</html>

进阶配置

引入 .vue 单文件与Vue-loader

.vue单文件组件需要使用 vue-loader 转换处理 
一个 .vue 文件包括 template script style 三部分

$ touch app.vue
    app 文件夹下 新建 app.vue 

vim app.vue

<template>
    <div> 你好,单文件组件</div>
</template>

<script>
    export default {

    }
</script>

<style scoped >
    div {
        color:red;
    }
</style>

scoped 表示当前的CSS只在当前组件内有效,如果不加,会应用到整个项目,lang=‘less’ 表示使用 less 预编译处理

使用 .vue 文件需要先安装 vue-loader vue-style-loader 等加载器并做配置 
另外要使用ES6语法,需要安装 babel 和 babel-loader 等加载器。

$ npm install -S vue
$ npm install -D vue-loader
$ npm install -D vue-style-loader
$ npm install -D vue-template-compiler
$ npm install -D vue-hot-reload-api
$ npm install -D babel
$ npm install -D babel-loader
$ npm install -D babel-core
$ npm install -D babel-plugin-transform-runtime
$ npm install -D babel-preset-es2015
$ npm install -D babel-runtime

安装完成后,添加配置

vim webpack.config.js 来支持对 .vue 以及 ES6 的解析;

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
    entry: {
        app: './app'
    },
    output: {
        path: path.join(__dirname,'./public'),
        publicPath: '/public/',
        filename: 'main.js'
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader:'vue-loader',
                options: {
                    loaders: {
                        css: ExtractTextPlugin.extract({
                            use:'css-loader',
                            fallback:'vue-style-loader'
                        })
                    }
                }
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test:/\.css$/,
                // use: [
                //     'style-loader',
                //     'css-loader'
                // ]
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',
                    fallback:'style-loader'
                })
            }
        ]
    },
    plugins:[
        //重命名提取后的CSS文件
        new ExtractTextPlugin("main.css")
    ]

};

module.exports = config;

vue-loader 在编译 .vue 文件时,会对

// document.getElementById('app').innerHTML = 'Hello webpack.’;

import './style.css';
import App from './app/app.vue';
import Vue from 'vue';

new Vue({
    el: '#app',
    render: h => h(App)    //这里不能直接写为components: { App },template:’<App></App>’,会报错

})

然后就可以

$ npm run dev 在浏览器中可以看到app.vue组件的内容替换了index.html 中的 id =‘app' 的 div

生产环境

进一步配置webpack

安装 url-loader file-loader 来支持图片、字体等文件;

$ npm install url-loader file-loader -D

vim webpack.config.js

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
    entry: {
        app: './app'
    },
    output: {
        path: path.join(__dirname,'./public'),
        publicPath: '/public/',
        filename: 'main.js'
    },
    module: {
        rules: [
            {
                test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
                loader: 'url-loader?limit=1024'
            },
            {
                test: /\.vue$/,
                loader:'vue-loader',
                options: {
                    loaders: {
                        css: ExtractTextPlugin.extract({
                            use:'css-loader',
                            fallback:'vue-style-loader'
                        })

                    },

                }
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test:/\.css$/,
                // use: [
                //     'style-loader',
                //     'css-loader'
                // ]
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',
                    fallback:'style-loader'
                })
            }
        ]
    },
    plugins:[
        //重命名提取后的CSS文件
        new ExtractTextPlugin("main.css")
    ]

};

module.exports = config;

当遇到 .gif .png .ttf 等格式文件时,url-loader 会把它们一起编译到 public 目录下, “?limit=1024”是指如果这个文件小于1kb,就以base64 的形式加载,不会生成一个文件。 
在app.vue 中加载一个图片。

vim app.vue

<template>
    <div> 
        <h1>你好,单文件组件</h1>
        <p>
            nice to see you!
        </p>
        <img src="./img/snow.jpg" width="300">
    </div>
</template>

<script>
    export default {
        name:'app',
        data(){
            return {

            }
        }

    }
</script>

<style scoped lang='less'>
    div {
        color:red;
        p {
            color:blue;
        }
    }
</style>

打包上线

打包后的产物: 
单页面富应用(SPA)最终只有一个html 文件,其余都是静态资源,实际部署到生产环境时,一般会将html 挂在后端程序下,由后端路由渲染这个页面,将所有的静态资源(CSS JS、image、iconfont等)单独部署到CDN,当然也可以和后端程序部署在一起,这样就实现了前后端完全分离。 
我们在webpack 的output 选项里已经指定了path 和publicPath ,打完包后,所有的资源都会在dailypaper/public 目录下。

下面是两个打包会用到的依赖, 使用NPM 安装

$ npm install webpack-merge -D
$ npm html-webpack-plugin -D

为了方便开发和生产环境的切换,我们在 dailypaper 目录下再建一个用于生产环境的配置文件 webpack.prod.config.js

vim webpack.prod.config.js

var webpack = require('webpack');
var HtmlwebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var merge = require('webpack-merge');
var webpackBaseConfig = require('./webpack.config.js');

//清空基本配置的插件列表
webpackBaseConfig.plugins=[];

module.exports=merge(webpackBaseConfig,{
    output: {
        publicPath: '/public_CDN/',
        //将入口文件重命名为带有20位hash值的唯一文件
        filename: 'static/js/[name].[hash].js'    //filename定义的路径就在打包配置的public文件夹下
    },
    plugins: [
        new ExtractTextPlugin({
            //提取CSS, 并重命名为带有20位hash值的唯一文件
            filename: 'static/css/[name].[hash].css',
            allChunks: true
        }),
        //定义当前的code 环境为生产环境
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: '"production"'
            }
        }),
        //压缩 JS
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            }
        }),
        //提取模板,并保存入口html文件
        new HtmlwebpackPlugin({
            filename: 'index_prod.html',//在public文件夹下,index_prod.html与static在同一目录下,
            template: './index.ejs',
            inject: false
        })
    ]
})

其中/public_CDN/需要修改为部署存放static文件夹的CDN服务器地址。 
上面安装的web pack-merge 模块就是用于合并两个webpack的配置文件,所以prod的配置是在web pack_config.js的基础上扩展的,静态资源大部分场景下都有缓存(304),更新上线后一般都希望用户能及时地看到内容,所以给打包后的CSS和JS文件的名称都加了20位的hash值,这样文件名就唯一了,只要不对html 设置缓存,上线后就能加载最新的静态资源。 
Html-webpack-plugin 是用来生成 .html 文件的, 它通过 template 选项来读取指定的模板 index.ejs, 然后输出到 filename 指定的目录, 也就是 public/index_prod.html。

下面是模板 index.ejs 动态设置了静态资源的路径和文件名 该文件在dailypaper目录下 
vim index.ejs

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>dailypaper</title>
    <link rel="stylesheet" type="text-css" href="<%= htmlWebpackPlugin.files.css[0] %>">
</head>
<body>
    <div id="app">

    </div>
    <script type='text/javascript' src="<%= htmlWebpackPlugin.files.js[0] %>"></script>
</body>
</html>

ejs 是一个JavaScript 模板库,用来从JSON 数据中生成HTML 字符串, 常用语Node.js

vim webpack.config.js

var path = require('path');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var config = {
    entry: {
        app: './app'
    },
    output: {
        path: path.join(__dirname, './public/'),
        publicPath: '/public/‘,
        filename: 'main.js'
    },
    module: {
        rules: [{
                test: /\.(gif|jpg|png|woff|svg|eot|ttf)\??.*$/,
                loader: 'url-loader?limit=1024&name=images/[hash:8].[name].[ext]’   //打包多个图片时
                //name 字段指定了在打包根目录(output.path)下生成名为 images 的文件夹,并在原图片名前加上8位 hash 值
            },
            {
                test: /\.vue$/,
                loader: 'vue-loader',
                options: {
                    loaders: {
                        css: ExtractTextPlugin.extract({
                            use: 'css-loader',
                            fallback: 'vue-style-loader'
                        })


                    },

                }
            },
            {
                test: /\.js$/,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                // use: [
                //     'style-loader',
                //     'css-loader'
                // ]
                use: ExtractTextPlugin.extract({
                    use: 'css-loader',
                    fallback: 'style-loader'
                })
            }
        ]
    },
    plugins: [
        //重命名提取后的CSS文件
        new ExtractTextPlugin("main.css")
    ]

};

module.exports = config;
$ npm run build     //打包
此时打包后的 index_prod.html在public 文件夹下,打包后的代码如下所示

打包之后的Index_prod.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>dailypaper</title>
    <link rel="stylesheet" type="text-css" href="/public_CDN/static/css/app.ba3073bb7bb28cda7d30.css">
</head>
<body>
    <div id="app">

    </div>
    <script type='text/javascript' src="/public_CDN/static/js/app.ba3073bb7bb28cda7d30.js"></script>
</body>
</html>

打包之后的目录如下

打包目录

posted @ 2018-09-04 22:59  caseywei  阅读(144)  评论(0编辑  收藏  举报