先进级成webpack四吧,在找一份相对完整的Webpac

2019-05-06 03:56 来源:未知

1. 移除了commonchunk插件,改用了optimization属性进行更加灵活的配置 ,不过稍微不注意,就会有问题,如

 

1. 搭建个服务器

既然是Demo,至少就得有一个服务器,用node来搭建一个简单的服务器,处理各种资源的请求返回

韦德娱乐1946网页版 1

新建一个服务器文件server.js,以及页面文件目录views,其他资源文件目录public

服务器文件很简单,请求什么就返回什么,外加了一个gzip的功能

let http = require('http'),
    fs = require('fs'),
    path = require('path'),
    url = require('url'),
    zlib = require('zlib');

http.createServer((req, res) => {
    let {pathname} = url.parse(req.url),
        acceptEncoding = req.headers['accept-encoding'] || '',
        referer = req.headers['Referer'] || '',
        raw;

    console.log('Request: ', req.url);

    try {
        raw = fs.createReadStream(path.resolve(__dirname, pathname.replace(/^//, '')));

        raw.on('error', (err) => {
            console.log(err);

            if (err.code === 'ENOENT') {
                res.writeHeader(404, {'content-type': 'text/html;charset="utf-8"'});
                res.write('<h1>404错误</h1><p>你要找的页面不存在</p>');
                res.end();
            }
        });

        if (acceptEncoding.match(/bgzipb/)) {
            res.writeHead(200, { 'Content-Encoding': 'gzip' });
            raw.pipe(zlib.createGzip()).pipe(res);
        } else if (acceptEncoding.match(/bdeflateb/)) {
            res.writeHead(200, { 'Content-Encoding': 'deflate' });
            raw.pipe(zlib.createDeflate()).pipe(res);
        } else {
            res.writeHead(200, {});
            raw.pipe(res);
        }
    } catch (e) {
        console.log(e);
    }
}).listen(8088);

console.log('服务器开启成功', 'localhost:8088/');

 

2. 设置基础项目目录

页面文件假设采用每一类一个目录,目录下的tpl为源文件,另外一个为生成的目标页面文件

韦德娱乐1946网页版 2

/public目录下,基本配置文件就放在根目录下,JS,CSS,Image等资源文件就放在/public/static目录下

我们要利用package.json文件来管理编译构建的包依赖,以及设置快捷的脚本启动方式,所以,先在/public目录下执行 npm init 吧

public/static/dist目录用来放置编译后的文件目录,最终页面引用的将是这里的资源

public/static/imgs目录用来放置图片源文件,有些图片会生成到dist中

public/static/libs目录主要用来放置第三方文件,也包括那些很少改动的文件

public/static/src 用来放置js和css的源文件,相应根目录下暴露一个文件出来,公共文件放到相应子目录下(如js/components和scss/util)

韦德娱乐1946网页版 3 韦德娱乐1946网页版 4

最后文件结构看起来是这样的,那就可以开干了

 

 

四、Webpack配置在Demo中的应用

下面以一个相对完整的基础Demo着手,介绍一下几个基本功能该如何配置

Demo项目地址   建议拿来练练

韦德娱乐1946网页版 5

韦德娱乐1946网页版 6

韦德娱乐1946网页版 7

 

3. 默认的提取公共模块机制可能会产生意外的结果,尽量取消默认后再自定义

 

Webpack已经出来很久了,相关的文章也有很多,然而比较完整的例子却不是很多,让很多新手不知如何下脚,下脚了又遍地坑

说实话,官方文档是蛮乱的,而且有些还是错的错的。。很多配置问题只有爬过坑才知道

本文首先介绍Webpack的一些基础知识,然后以一个已经完成的小Demo,逐一介绍如何在项目中进行配置

该Demo主要包含编译Sass/ES6,提取(多个)CSS文件,提取公共文件,模块热更新替换,开发与线上环境区分,使用jQuery插件的方式、页面资源引入路径自动生成(可指定生成位置),热更新编译模版文件自动生成webpack服务器中的资源路径,编写一个简单的插件,异步加载模块 等基础功能

应该能帮助大家更好地在项目中使用Webpack3来管理前端资源

本文比较啰嗦,可以直接看第四部分 style="text-decoration: underline;"> style="color: #339966;"> style="color: #339966; text-decoration: underline;">Webpack3配置在Demo中的应用,或者直接去 style="text-decoration: underline;"> style="color: #339966;"> style="color: #339966; text-decoration: underline;">Fork这个Demo边看边玩

10. 引入 dllplugin动态链接库方案,将第三方库单独打包,再链入我们的webpack项目中

 6. 编译Sass成CSS,嵌入到页面<style>标签中,或将其提取出(多个)CSS文件来用<link>引入

sass的编译node-sass需要python2.7的环境,先确定已经安装并设置了环境变量

npm i sass-loader node-sass style-loader css-loader --save-dev

类似的,设置一下loader规则

不过这里要设置成使用提取CSS文件的插件设置了,因为它的disable属性可以快速切换是否提取CSS(这里设置成生产环境才提取)

好好看这个栗子,其实分三步:设置(new)两个实例,loader匹配css和sass两种文件规则,在插件中引入这两个实例

提取多个CSS文件其实是比较麻烦的,但也不是不可以,方法就是设置多个实例和对应的几个loader规则

这里把引入的sass当做是自己写的文件,提取成一个文件[name].css,把引入的css当做是第三方的文件,提取成一个[name]_vendor.css,既做到了合并,也做到了拆分,目前还没想到更好的方案

上面提到过,output的path设置成了/public/static/dist/js ,所以这里的filename 生成是基于上面的路径,可以用../来更换生成的css目录

[contenthash]是css文件内容的hash,在引用它的地方有体现

fallback表示不可提取时的代替方案,即上述所说的使用style-loader嵌入到<style>标签中

npm i extract-text-webpack-plugin --save-dev


ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')

/ 对import 引入css(如第三方css)的提取
    cssExtractor = new ExtractTextWebpackPlugin({
        // 开发环境下不需要提取,禁用
        disable: !isProduction,
        filename: '../css/[name]_vendor.css?[contenthash:8]',
        allChunks: true
    })

    // 对import 引入sass(如自己写的sass)的提取
    sassExtractor = new ExtractTextWebpackPlugin({
        // 开发环境下不需要提取,禁用
        disable: !isProduction,
        filename: '../css/[name].css?[contenthash:8]',
        allChunks: true
    });




// 插件配置
    plugins: [
        // 从模块中提取CSS文件的配置
        cssExtractor,
        sassExtractor
    ]






module: {
        rules: [{
            test: /.css$/,
            // 提取CSS文件
            use: cssExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: 'style-loader',
                use: [{
                        loader: 'css-loader',
                        options: {
                            // url: false,
                            minimize: true
                        }
                    },
                    // 'postcss-loader'
                ]
            })
        }, {
            test: /.scss$/,
            // 编译Sass文件 提取CSS文件
            use: sassExtractor.extract({
                // 如果配置成不提取,则此类文件使用style-loader插入到<head>标签中
                fallback: 'style-loader',
                use: [
                    'css-loader',
                    // 'postcss-loader',
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true,
                            outputStyle: 'compressed'
                        }
                    }
                ]
            })
        }

这样一来,如果在不同文件中引入不同的文件,生成的css可能长这样

// ./home.js
import '../../libs/bootstrap-datepicker/datepicker3.css';

import '../../libs/chosen/chosen.1.0.0.css';

import '../../libs/layer/skin/layer.css';

import '../../libs/font-awesome/css/font-awesome.min.css';


import '../scss/detail.scss';




// ./detail.js
import '../../libs/bootstrap-datepicker/datepicker3.css';

import '../../libs/chosen/chosen.1.0.0.css';

import '../../libs/layer/skin/layer.css';

import '../scss/detail.scss';

韦德娱乐1946网页版 8

// ./home.html
<link href="/public/static/dist/js/../css/common_vendor.css?66cb1f48" rel="stylesheet">
<link href="/public/static/dist/js/../css/common.css?618d2a04" rel="stylesheet">
<link href="/public/static/dist/js/../css/home_vendor.css?12a314c8" rel="stylesheet">
<link href="/public/static/dist/js/../css/home.css?c196fc33" rel="stylesheet">




// ./detail.html
<link href="/public/static/dist/js/../css/common_vendor.css?66cb1f48" rel="stylesheet">
<link href="/public/static/dist/js/../css/common.css?618d2a04" rel="stylesheet">

可以看到,公共文件也被提取出来了,利用HtmlWebpackPlugin就能将其置入了

另外,可以看到这里的绝对路径,其实就是因为在output中设置了publicPath为/public/static/dist/js/

 

当然了,也不是说一定得在js中引入这些css资源文件,你可以直接在页面中手动<link>引入第三方CSS

我这里主要是基于模块化文件依赖,以及多CSS文件的合并压缩的考虑才用这种引入方式的

 

14. 自定义HtmlWebpackPlugin插件编译模版文件生成的JS/CSS插入位置

HtmlWebpackPlugin主要用来编译模版文件,生成新的页面文件

new HtmlWebpackPlugin({
            template: '../../parent/parent_index_src.html',
            filename: '../../../../parent/parent_index.tpl',
            chunks: ['common', 'parent'],
            inject: true
        }),

一般来说会这样用,可以同时将JS资源与CSS资源插入到页面中(可自动配hash值),非常方便

但是修改inject属性只会不插入或插入到</head>或</body>标签之前,自定义不了插入位置

上述第八点提到了利用插件来调整生成<script>标签,其实还有更便捷的方法可以实现:使用其支持的模版引擎

假设现在是smarty页面,有个公共父模版文件,很多子页面套用这个文件,那么它可以长成这个样子

<!-- 父页面  -->
<!DOCTYPE html>
<html>
    <head>
        <title>某个系统</title>
        <meta charset="utf-8">
        <meta lang="zh-CN">

        <% for(var key in htmlWebpackPlugin.files.css) { %>
        <link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[key] %>">
        <% } %>

        <{block name="page_css"}><{/block}>
    </head>
    <body>
        <section class="container">
            父页面
        </section>

        <{block name="page_content"}><{/block}>

        <script src="/public/static/js/jquery.min.js"></script>

        <% for(var key in htmlWebpackPlugin.files.js) { %>
        <script src="<%= htmlWebpackPlugin.files.js[key] %>"></script>
        <% } %>

        <{block name="page_js"}><{/block}>
        <script src="http://localhost:8188/dist/js/common.js"></script>
        <script src="http://localhost:8188/dist/js/parent.js"></script>
    </body>
</html>

<!-- 子页面 -->

<{extends file="../parent/parent_index.tpl"}>


<{block name="page_css"}>
<% for(var key in htmlWebpackPlugin.files.css) { %>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[key] %>">
<% } %>
<{/block}>


<{block name="page_content"}>
<h1>子页面</h1>
<div>

</div>
<{/block}>



<{block name="page_js"}>
<% for(var key in htmlWebpackPlugin.files.js) { %>
<script src="<%= htmlWebpackPlugin.files.js[key] %>"></script>
<% } %>
<{/block}>

这里,为了实现子页面插入到父页面之后,还能保持CSS与JS资源放在正确的位置,需要指定一个编译后的生成位置

使用到了Webpack内置支持的ejs模版,并使用到了其htmlWebpackPlugin变量,里面携带了本次编译的一些信息,我们可以直接输出来插入资源,然后再设置 inject: false就行了

下面是一个例子的输出,更多的就去看文档吧

"htmlWebpackPlugin": {
  "files": {
    publicPath : "", 
    "css": [],
    "js": [ "js/main.ae8647e767cd76e54693.bundle.js"],
    "chunks": {
      "main": {
        "size":23,
        "entry": "js/main.ae8647e767cd76e54693.bundle.js", 
        "css": [],
        "hash":"ae8647e767cd76e54693",
      }
    },
    manifest : ""
  },
  "options":{
        template : "C:\dev\webpack-demo\node_modules\.2.28.0@html-webpack-plugin\lib\loader.js!c:\dev\webpack-demo\index.html",    
    filename : "index.html",    
    hash : false,    
    inject : false,    
    compile : true,    
    favicon : false,    
    minify : false,        
    cache : true,    
    showErrors : true,    
    chunks : ["main"],    
    excludeChunks : [],    
    title : "I am title",    
    xhtml : false    
    }
}

 

 

 15. 热更新编译模版文件自动生成webpack服务器中的资源路径

热更新时,webpack的devServer默认只会将模块编译到内存中,编译到我们设置的服务器里,不会编译生成到本地开发目录中

这并不算什么问题,问题是我们需要在页面中手动引入服务器的模块,比如

<script src="http://localhost:8188/dist/js/common.js"></script>

        <script src="http://localhost:8188/dist/js/parent.js"></script>

使用热更新时手动添加,不使用时手动删掉才上传代码,这还好,但是,我们有模版文件

假设模版文件为a_src.html ,需要编译成a.html,我们实际项目中要访问的文件是编译后的a.html文件,而我们只能在源文件a_src.html中做改动

使用热更新的时候,并不能将源文件编译写到新文件上,我们只能换着法子访问源文件或者直接改动新文件并复制一份到源文件中,而且还得手动添加热更新的服务器模块路径

太麻烦了,那就在热更新的时候也编译模版文件吧,使用HtmlWebpackHarddiskPlugin 插件自动生成资源引用路径,同时在源文件的更改可以自动编译写到新文件中

// 安装
 npm install --save-dev html-webpack-harddisk-plugin



var HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');


// 配合htmlWebpackPlugin使用,加上参数alwaysWriteToDisk
new HtmlWebpackPlugin({
            template: '../../main/protected/views/flow/a_src.html',
            filename: '../../../../main/protected/views/flow/a.htmll',
            chunks: ['a'],
            inject: false,
            alwaysWriteToDisk: true
        }),
        new HtmlWebpackPlugin({
            template: '../../main/protected/views/parent/parent_src.html',
            filename: '../../../../main/protected/views/parent/parent.html',
            chunks: ['common', 'parent'],
            inject: false,
            alwaysWriteToDisk: true
        }),
    // 调用
        new HtmlWebpackHarddiskPlugin()

然后在源模版文件里,配合上一点的ejs模版生成出来就行了,可以自动检测是生成环境的路径还是开发环境的热更新路径 解放了劳动力

源模版文件:

<!-- 编译后脚本 -->
        <% for(var key in htmlWebpackPlugin.files.js) { %>
        <script src="<%= htmlWebpackPlugin.files.js[key] %>"></script>
        <% } %>

development:

// 文件输出配置
    output: {
        publicPath: 'http://localhost:8188/dist/js/',
    },

 <!-- 编译后脚本 -->

        <script src="http://localhost:8188/dist/js/common.js"></script>

        <script src="http://localhost:8188/dist/js/parent.js"></script>

production:

// 文件输出配置
    output: {
        publicPath: '/public/assets/dist/js/'
    },

 <!-- 编译后脚本 -->

        <script src="/public/assets/dist/js/common.js?784109bb"></script>

        <script src="/public/assets/dist/js/parent.js?997487cf"></script>

 

 

 10. 模块热更新替换的正确姿势

在开发环境下,如果做到模块的热更新替换,效果肯定是棒棒的。生成环境就先不用了

在最初的时候,只是做到了热更新,并没有做到热替换,其实都是坑在作祟

热更新,需要一个配置服务器,Webpack集成了devServer的nodejs服务器,配置一下它

// 开发环境设置本地服务器,实现热更新
    devServer: {
        contentBase: path.resolve(__dirname, 'static'),
        // 提供给外部访问
        host: '0.0.0.0',
        port: 8188,
        // 设置页面引入
        inline: true
    },

正常的话,启动服务应该就可以了吧

webpack-dev-server --config webpack.config.dev.js

要记住,devServer编译的模块是输出在服务器上的(默认根目录),不会影响到本地文件,所以要在页面上手动设置一下引用的资源

<script src="http://localhost:8188/common.js"></script>
<script src="http://localhost:8188/home.js"></script>

浏览器访问,改动一下home.js文件,这时应该可以看到页面自动刷新,这就是热更新了

TAG标签: 韦德娱乐1946
版权声明:本文由韦德娱乐1946_韦德娱乐1946网页版|韦德国际1946官网发布于韦德娱乐1946网页版,转载请注明出处:先进级成webpack四吧,在找一份相对完整的Webpac