资讯专栏INFORMATION COLUMN

webpack 简易配置入门教程

JackJiang / 2007人阅读

摘要:使用等预处理器编写可以将你项目中的所有文件,处理成浏览器能识别的文件。测试打包基本的配置就完成了。修改处理文件执行顺序是从右到左修改一下入口文件中的样式引入打包测试完美通过。这时可以使用提供的配置来使引入文件的时候变得更加方便简单。

本文正文链接

最近公司弄了个有150+页面的项目,心想,终于有机会可以去学习webpack了,以前想学却没有实际项目去引导逼迫去学,现在终于领略到了webpack的强大了。

什么是webpack

在前端的项目开发中,总有大量的页面和样式需要处理,而维护这些文件也成了头疼的问题。

为了简化开发,于是就有很多好的开发方式,如:

模块化开发。每个功能模块都分开成一个个独立的组件,需要的时候再引入。

scss等预处理器。

使用pug, jade 更快编写HTML。

...

这些方式确实可以大大提高开发效率,但是每种方式都有自己的打包方式,还有兼容性处理,如果纯手动处理,必然会增加工作量。

但是,现在有了webpack,上述问题基本解决了,一个webpack就可以处理各种繁琐的过程,给你一个清爽,快速的开发环境。

WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。

简单的来说,在项目开发中,

你可以使用js,es6/7,甚至ts开发。

es6/es7, .ts => .js

使用stylus, scss, less 等预处理器编写css

.scss/.less => .css

webpack可以将你项目中的所有文件,处理成浏览器能识别的文件。

开始使用webpack

先新建一个练手用的空文件夹 $ mkdir webpack-demo ,并进入该文件夹。

新建 package.json.

$ npm init

安装webpack及其基本插件。

$ npm i -D webpack extract-text-webpack-plugin html-webpack-plugin css-loader file-loader style-loader url-loader

其中:

extract-text-webpack-plugin : 该插件主要为了抽离css样式,可以将css从打包的js中抽离出来。以link方式引入样式。

html-webpack-plugin : 该插件主要是用于生成html文件,并可以根据入口文件来引入相应的文件。

css-loader : 解析css文件中的 importrequire ,并处理他们。

style-loader : 将css样式通过 style 标签注入到html文件中。

file-loader : 指明webpack将所引入的对象,并返回一个公网能访问的url地址。

url-loader : 将文件转换成 base64编码。

配置webpack。

新建一个配置文件: $ touch webpack.config.js

var webpack = require("webpack");
var path = require("path");

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");

var webpackConfig = {
    // 设置入口文件。
    entry: "./src/js/index.js",
    output: {
        // 设置输出文件夹
        path: path.join(__dirname, "dist"),
        // 设置公用文件夹路径
        publicPath: "/",
        // 设置输出的js文件的名字规则。
        // [name] 为chunk中的名称
        // [hash] 为webpack生成的哈希值
        filename: "js/[name].[hash].bundle.js"
    },
    module: {
        rules: [{
            // 处理css文件
            test: /.css$/,
            loader: "style-loader!css-loader"
        }, {
            // 处理html文件,并处理img 中 src 和 data-src 的引入路径
            test: /.html$/,
            loader: "html-loader?attrs=img:src img:data-src"
        }, {
            // 处理字体文件
            test: /.(woff|woff2|ttf|eot|svg)(?v=[0-9].[0-9].[0-9])?$/,
            loader: "file-loader?name=./fonts/[name].[ext]"
        }, {
            // 处理图片,并将8k以下的图片转为base64编码
            test: /.(png|jpg|gif)$/,
            loader: "url-loader?limit=8192&name=./img/[hash].[ext]"
        }]
    },
    plugins: [
        // 公共js提取
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendors", // 将公共模块提取,生成名为`vendors`的chunk
            // minChunks: 3 // 提取至少3个模块共有的部分
        }),
        // 提取公共css样式
        new ExtractTextPlugin("./css/[name].css"),
        // 处理html文件。
        new HtmlWebpackPlugin({
            filename: "./view/index.html", //生成的html存放路径,相对于path
            template: "./src/view/index.html", //html模板路径
            inject: "body", //js插入的位置,true/"head"/"body"/false
            hash: true, //为静态资源生成hash值
            // chunks: ["vendors", allDirs[i] + "/" + matches[1]], //需要引入的chunk,不配置就会引入所有页面的资源
            minify: { //压缩HTML文件
                removeComments: true, //移除HTML中的注释
                collapseWhitespace: false //删除空白符与换行符
            }
        })
    ],
    // 设置开发服务器
    devServer: {
        contentBase: path.join(__dirname, "dist/"),
        host: "localhost",
        port: 9090,
        inline: true
    }
}

module.exports = webpackConfig

测试配置文件:
先设置开发文件夹目录:

-   webpack-demo
    +   node_modules
    -   src
        +   js      // 存放js文件
        +   css     // 存放css样式
        +   view    // 存放模板文件

        webpack.config.js
        package.json

新建一个 html 文件: $ touch ./src/view/index.html




    
    
    
    Hello World


    

Hello World

This is from webpack-demo

新建css文件: $ touch ./src/css/index.css

h2{
    color: red;
    opacity: 0.5;
    transform: rotateZ(-10deg);
}
p{
    color: green;
}

新建js文件: $ touch ./src/js/index.js

// 引入css文件。
require("../css/index.css")

console.log("hello world");

测试打包: $ webpack
OK!基本的配置就完成了。

我们可以看到,在项目中多了一个dist文件夹,里面存放的就是刚刚打包好的文件。打开index.html(需要在服务器中打开,并且服务器根目录为dist)可以看到,生成的html文件,征程显示我们写的内容,css样式则直接写入了style标签当中,而且自动引入了两个js文件,其中,vendors是带有公共部分的js文件,index则是我们一开始写的js逻辑文件。

处理scss文件。

既然都用到了webpack自动打包了,那也顺便使用webpack去处理scss文件(个人爱好是scss,less的处理同理),顺便也处理完css中的其他兼容性问题和浏览器前缀问题吧(程序员的思维就是,懒)。

现在css中需要处理的有:

浏览器前缀和大部分兼容性问题: autoprefixer

flex 的兼容性问题: postcss-flexibility

opacity 兼容IE: postcss-opacity

颜色兼容性问题: postcss-color-rgba-fallback

scss文件处理: sass-loader 同时需要依赖 node-sass

压缩css文件: cssnano

安装上书postcss-loader的插件: $ npm i -D autoprefixer postcss-flexibility postcss-opacity postcss-color-rgba-fallback sass-loader node-sass

现在在webpack中处理css的问题,基本都是通过一个 postcss-loader 去完成所有的处理问题。

先新建一个文件夹,用于存放所有的scss文件: $ mkdir ./src/scss

再新建一个index.scss, $ touch ./src/scss/index.scss

body{
    background: black;
    color: white;
    h2{
        transform: translateX(10px) rotateZ(-10deg);
        color: red;
        opacity: 0.5;
    }
}

将postcss的加载器中需要的多带带提取出来放在一个配置文件中: $ touch postcss.config.js

module.exports = {
    plugins: [
        // minify css
        require("cssnano")({
            preset: "default"
        }),
        // 处理css前缀
        require("autoprefixer")({
            browserslist: [
                "> 1%",
                "last 2 versions",
                "Edge",
                "ie >= 9"
            ]
        }),
        // 处理flex浏览器兼容性
        require("postcss-flexibility"),
        // 处理css中rgba颜色代码
        require("postcss-color-rgba-fallback"),
        // 处理css中opacity的IE兼容性。
        require("postcss-opacity")
    ]
}

修改 webpack.config.js:

var webpackConfig = {
    ...
    module: {
        rules: [{
            // 处理css文件
            test: /.(scss|sass|css)$/,
            // loader: "css-loader?importLoaders=1!postcss-loader!sass-loader",
            // loader执行顺序是从右到左:sass-loader -> postcss-loader -> css-loader
            use: [
                "style-loader",
                {
                    loader: "css-loader",
                    options: {
                        // // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
                        importLoaders: 2
                    }
                },
                "postcss-loader",
                "sass-loader"
            ]
        },
        ...
        ]
    }
    ...
}

module.exports = webpackConfig

修改一下入口文件中的样式引入: $ vim ./src/js/index.js

require("../scss/index.scss")

console.log("hello world");

打包测试:

完美通过。

处理pug/jade文件

项目有很多的页面,而且页面之间也有很多相同的页面,之前写惯了vue的组件,所以注册我们也引入了pug作为前端模板引擎。 pug 的前身就是 jade ,所以语法什么都得基本都是一致的。具体的看 官网 。

和处理css的一样,先要安装加载器。 $ npm i -D pug pug-loader

新建一个简单的页面: $ touch ./src/view/index.pug

html
    title   Test.html
body
    h2  Welcome to pug.
    p   This is from index.pug

修改一下配置文件中的html模板入口:

var webpackConfig = {
    ...
    plugins: [
        // 公共js提取
        new webpack.optimize.CommonsChunkPlugin({
            name: "vendors", // 将公共模块提取,生成名为`vendors`的chunk
        }),
        // 提取公共css样式
        new ExtractTextPlugin("./css/[name].css"),
        // 处理html文件。
        new HtmlWebpackPlugin({
            filename: "./view/index.html", //生成的html存放路径,相对于path
            template: "./src/view/index.pug", //html模板路径
            inject: "body", //js插入的位置,true/"head"/"body"/false
            hash: true, //为静态资源生成hash值
            chunks: ["vendors", "index"], //需要引入的chunk,不配置就会引入所有页面的资源
            minify: { //压缩HTML文件
                removeComments: true, //移除HTML中的注释
                collapseWhitespace: false //删除空白符与换行符
            }
        })
    ],
    ...
}

module.exports = webpackConfig

重新编译打包:

使用 babel 来“编译”你的js

在项目开发中,难免会遇到使用 es6 ,甚至 es7 去编写js。但是大部分浏览器却不支持这些语法,这时候,就需要 babel-loader 来处理js,并将其转换为浏览器能识别的 es5 语法。

还是要安装依赖: $ npm i -D babel-loader babel-core babel-preset-es2015

如果用上了es7 的语法,就要根据不同阶段语法提案的转码规则(共有4个阶段),选装一个:

$ npm i -D babel-preset-stage-0
$ npm i -D babel-preset-stage-1
$ npm i -D babel-preset-stage-2
$ npm i -D babel-preset-stage-3

新建一个 .babelrc babel配置文件: $ touch .babelrc

{
    "presets": ["es2015"],
    "plugins": []
}

修改 webpack 配置文件:

var webpackConfig = {
    ...
    module: {
        rules: [{
            test: /.js$/,
            // 不编译 node_modules 下的文件
            exclude: /node_modules/,
            loader: "babel-loader"
        }]
    }
    ...
}

module.exports = webpackConfig

在 index.js 中写个 es6 的语法:

require("../scss/index.scss")

console.log("hello world");

((message) => {
    console.log(message);
})("message from es6")

let step = 2;
var add = number => number*=step

console.log(add(2));

来,打包看看:


完美。

配置多文件入口

项目有多个页面,每个页面都对应着一个js入口和一个页面,但是,入口 entry 和 html-webpack-plugin 每次只能配置一个具体的入口文件,如果每增加一个页面就要去配置,那么这无形之中增加了工作量,因此,我们需要一个通用的入口文件。

既然在node中可以访问文件夹并读取其中的文件名,那么我们可以使用node来去循环读取文件夹下的js文件,并自动添加至入口配置中:

新建一个config 文件夹,以存放webpack可变的配置,方便以后修改: $ mkdir config

因为遍历入口文件都是一样的操作流程,所以先写一个工具包:$ touch config/utils.js

var fs = require("fs");
// 递归遍历文件夹,获取入口文件
function getAllFiles(dirRoot, type){
    var filterReg = new RegExp("."+type+"$");
    function getAllFileFromDir(root) {
        var res = [], files = fs.readdirSync(root)
        files.forEach((file) => {
            var pathname = root+"/"+file,
                state = fs.lstatSync(pathname)
            if (!state.isDirectory()) {
                // 过滤相对应的文件
                filterReg.test(pathname) && res.push(pathname)
                // res.push(pathname.replace(dir_root+"/", ""))
            }else{
                res = res.concat(getAllFileFromDir(pathname))
            }
        })
        return res
    }
    return getAllFileFromDir(dirRoot)
}

function getEntry(files, replaces){
    var entry = {}
    for (var i = 0; i < files.length; i++) {
        var filename = files[i]
        replaces.map((replace) => {
            filename = filename.replace(replace, "")
        })
        entry[filename] = files[i]
    }
    return entry
}

module.exports = {
    getAllFiles,
    getEntry
}

再新建一个 js 入口文件配置: $ touch config/webpack.entry.js

var path = require("path");
var utils = require("./utils.js")
var dir_root = path.resolve(__dirname, "../src/js");

// console.log(getAllFiles(dir_root));
var allFiles = utils.getAllFiles(dir_root, "js")
var entry = utils.getEntry(allFiles, ["js", dir_root+"/"])
console.log(entry);
module.exports = entry

同样的,页面入口文件也添加一个: $ touch config/webpack.plugins.js

var webpack = require("webpack")
var path = require("path");
var utils = require("./utils.js")

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");

var entry = require("./webpack.entry.js")

var plugins = [
    // 公共js提取
    new webpack.optimize.CommonsChunkPlugin({
        name: "vendors", // 将公共模块提取,生成名为`vendors`的chunk
        minChunks: 3 // 提取至少3个模块共有的部分
    }),
    // 提取公共css样式
    new ExtractTextPlugin("./css/[name].css"),
]
let dir_root = path.resolve(__dirname, "../src/view");
var pugFiles = utils.getAllFiles(dir_root, "pug")

pugFiles = utils.getEntry(pugFiles, [".pug", dir_root+"/"])

for (var key in pugFiles) {
    if (pugFiles.hasOwnProperty(key)) {
        let opt = {
            filename: "./view/"+ key +".html",
            template: pugFiles[key],
            hash: true,
            minify: { //压缩HTML文件
                removeComments: true, //移除HTML中的注释
                collapseWhitespace: false //删除空白符与换行符
            }
        }
        if (entry.hasOwnProperty(key)) {
            opt["chunks"] = ["vendors", key]
            opt["inject"]= "body"
        }
        console.log(opt);
        plugins.push(new HtmlWebpackPlugin(opt))
    }
}

module.exports = plugins

再次修改webpack的配置:

var entry = require("./config/webpack.entry.js")
var plugins = require("./config/webpack.plugins.js")

var webpackConfig = {
    entry,
    plugins,
    ...
}

module.exports = webpackConfig



可以看到,dist文件夹下,多了几个html文件和js文件。

其他处理

提取css到外部link,而非style标签
这个解决办法比较简单,只需要用 extract-text-webpack-plugin 插件将css提取出来即可:

{
    test: /.(scss|sass|css)$/,
    use: ExtractTextPlugin.extract({
        fallback: "style-loader",
        use: [{
                loader: "css-loader",
                options: {
                    // // 0 => no loaders (default); 1 => postcss-loader; 2 => postcss-loader, sass-loader
                    importLoaders: 2
                }
            },
            "postcss-loader",
            "sass-loader"
        ]
    })
}

再次打包的结果:

列出dis文件夹的目录树可以发现,多了一个css的文件夹。打开页面可以发现,页面中的style标签已经被link替代了。

每次打包旧的文件依旧存在
每次执行webpack打包(当然在实际开发中应该使用热更新服务器,不需要频繁打包)都会产生一堆新的js文件。

解决办法:

一是将打包的js文件的hash值去掉,这样就会新的打包js文件,将旧的覆盖。

二是使用 clean-webpack-plugin

var CleanWebpackPlugin = require("clean-webpack-plugin");
var plugins = [
    // 每次打包前都清空dist文件
    new CleanWebpackPlugin(["dist"], {
        root: path.resolve(__dirname, "../")
    }),
    // 公共js提取
    new webpack.optimize.CommonsChunkPlugin({
        name: "vendors", // 将公共模块提取,生成名为`vendors`的chunk
        // minChunks: 3 // 提取至少3个模块共有的部分
    }),
    // 提取公共css样式
    new ExtractTextPlugin("./css/[name].css"),
]

批量新建文件
因为每个页面基本都有3个文件:page.pug, page.js, page.scss,如果每次新加一个页面都要手动新建3个文件的话,效率太低下,能用命令行解决的,当然要用命令行解决啦。

先写个小脚本 newpage.sh:

#!/bin/sh
if [[ $1 ]]; then
    filename=$1
    touch ./src/js/$filename.js
    touch ./src/view/$filename.pug
    touch ./src/scss/$filename.scss
fi

使用方式就是: $ ./newpage.sh filename,要运行该脚本,就需要先将脚本设置为可执行: $ sudo chmod +x ./newpage.sh

还可以将它写进 npm 的 package.json 的命令中,则命令可以变为:npm run new -- filename

{
    "script": {
        "new": "./newpage.sh"
    }
}

定义路径常量
在编写js时,因为有可能js文件是在很多级的目录当中,如果每次都使用 .. 来定位上一层目录的话,那么这个定位就会十分繁琐。这时可以使用 webpack 提供的 resolve.alias 配置来使引入文件的时候变得更加方便简单。

resolve: {
    alias: {
        scss: path.resolve(__dirname, "src/scss"),
        js: path.resolve(__dirname, "src/js"),
        view: path.resolve(__dirname, "src/view"),
        assets: path.resolve(__dirname, "src/assets")
    }
}

这样,在 other.js 中,就可以直接使用 require("scss/about.scss") 而不需要写繁琐的 require("../../scss/about.scss")。这样就方便多了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84895.html

相关文章

  • webpack简易教程之loader

    摘要:一组链式的将按照先后顺序进行编译。在最后一个,返回所预期的。运行在中,并且能够执行任何可能的操作。用于对传递配置。分开的每个部分都相对于当前目录解析。 webpack自称能够打包任何文件,这句话咋听一下好像在吹牛逼,因为webpack本身只能理解JavaScript。但是由于webpack中有loader的存在,可以将所有类型的文件转换为webpack能够处理的有效模块,然后利用we...

    MobService 评论0 收藏0
  • Vuejs自己的构建工具

    摘要:然而,这些模板并不限制你自己对于使用的架构组织和选择类库。目前可用的模板包括全功能的,包括热加载,静态检测,单元测试一个简易的,以便于快速开始。 最近, 尤大在和人对喷的时候,悄然放出了一个大招,于是为了追赶他的步伐,赶紧试验了下,并且把原文给大家翻译下。 原文地址:Announcing vue-cli 译文源地址: Vuejs自己的构建工具 先上原文翻译: 最近有很多大量关于Reac...

    leoperfect 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    sutaking 评论0 收藏0
  • 关于Vue2一些值得推荐的文章 -- 五、六月份

    摘要:五六月份推荐集合查看最新的请点击集前端最近很火的框架资源定时更新,欢迎一下。苏幕遮燎沈香宋周邦彦燎沈香,消溽暑。鸟雀呼晴,侵晓窥檐语。叶上初阳乾宿雨,水面清圆,一一风荷举。家住吴门,久作长安旅。五月渔郎相忆否。小楫轻舟,梦入芙蓉浦。 五、六月份推荐集合 查看github最新的Vue weekly;请::点击::集web前端最近很火的vue2框架资源;定时更新,欢迎 Star 一下。 苏...

    khs1994 评论0 收藏0

发表评论

0条评论

JackJiang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<