Gadzan

搭建webpack环境

一 . 搭建一个webpack项目

首先你需要一个node.js (我的版本 node v8.9.4, npm v5.6.0 )
创建一个文件夹 mkdir webpack-my 进入文件夹 cd webpack-my
创建项目 npm init 一路回车
安装webpack webpack-cli(想要执行webpack的命令必须有这个包)
--save-dev 是只添加依赖到开发环境

npm install --save-dev webpack webpack-cli
window下执行应该有几条警告 警告虽然没多大关系但我们还是来看一下

WARN nomnom@1.8.1: Package no longer supported...

nomnom包过时了不用管它

WARN babel-preset-es2015@6.24.1

babel推荐让使用 babel-preset-env 我们下面再安装

WARN webpack-my@1.0.0 No repository field

没有仓库地址的警告可以在 npm init命令里设置或修改package.json:

"repository": {
    "type": "git",
    "url": "http://path.xxx"
}

或者设置 "private": true 设置为私有 webpack-my@1.0.0 No description 没写描述,基本同上...
两个 WARN SKIPPING OPTIONAL DEPENDENCY: fsevents@1.1.3 fsevent是mac osx系统的,警告忽略之...
(微强迫症,警告不看全不舒服...)

二 . 处理js文件

1 . 安装babel

处理js文件我们需要用到bable,先安装一下

cnpm install --save-dev babel-loader babel-core

2 . 安装 babel-preset-env

它用来转义es6等 babel-preset-env介绍

cnpm install --save-dev babel-preset-env
在根目录下创建 .babelrc 文件, 加入以下代码

{
    "presets": ["env"]
}

3 . 解决浏览器兼容及性能问题

为防止浏览器不支持 Promise/Object.assign/Array.from等还有性能问题,我们引入两个包:

cnpm install --save-dev babel-polyfill babel-plugin-transform-runtime
引入生产版本依赖 cnpm install --save babel-runtime
通过 .babelrc 添加配置

{
    "presets": [
        "env"
    ],
    "plugins": [
       "transform-runtime"
    ]
}

babel-polyfill 需要在 webpack中配置下面会说到

4 . 让我们来配置一下webpack :

创建 src/bundle文件夹作为我们存放/生成代码的地方
在项目根目录下创建 webpack.config.js 文件作为webpack的配置文件 path为node.js内置的,用来处理路径的, __dirname是node.js的全局属性,代表当前路径。将 babel-polyfill 加到你的 entry 数组中使用
配置js文件要经过babel转义

const path = require('path');
module.exports = {
    //entry为入口,webpack从这里开始编译
    entry: [
        "babel-polyfill",
        path.join(__dirname, './src/index.js')
    ],
    //output为输出 path代表路径 filename代表文件名称
    output: {
        path: path.join(__dirname, './bundle'),
        filename: 'bundle.js'
    },
    //module是配置所有模块要经过什么处理
    //test:处理什么类型的文件,use:用什么,include:处理这里的,exclude:不处理这里的
    module: {
        rules: [
            {
                test: /(\.jsx|\.js)$/,
                use: ['babel-loader'],
                include: path.join(__dirname , 'src'),
                exclude: /node_modules/
            }
        ]
    },
};

好了让我们来试验一下,在src里创建 text-0.js text-1.js text-2.js index.js 内容分别为:

export const Text0 = "小明";

export const Text1 = "在公司";

export const Text2 = "写代码";

import {Text0} from './text-0.js';
import {Text1} from './text-1.js';
import {Text2} from './text-2.js';

const textFun = (...arg) => {
    let P = document.createElement("p");
    P.innerHTML = arg.join(" ");
    document.getElementById('root').appendChild(P);
}
textFun(Text0,Text1,Text2);

5 . 使用webpack

控制台输入 npx webpack --config webpack.config.js npx是什么
根据webpack.config.js打包文件
等等出现了什么

`WARNING in configuration The 'mode' option has not been set, webpack will fallback to 'production' for this value. 
Set 'mode' option to 'development' or 'production' to enable defaults for each environment. You can also set it to 'none' to disable any default behavior. 
Learn more: https://webpack.js.org/concepts/mode/` 

原来是让我们设置开发或者生产模式
webpack.config.js 里设置

mode: 'development'

为了方便使用我们在 package.json 里加入webpack打包的命令方便我们使用修改 script

"scripts": {
    "build": "npx webpack --config webpack.config.js"
 },

这样再次运行我们直接输入 npm run build
js文件打包好了,让我们创建一个html页面看看效果吧,在bundle文件夹下创建 index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
        <script type="text/javascript" src="./bundle.js" charset="utf-8"></script>
    </body>
</html>

注意在这里写了一个script标签引入 bundle.js
打开html文件看看效果吧

如果你想看看打包出来的js文件,你可以在 webpack.config.js 里添加 devtool 属性

属性配置

简单的话直接配置 devtool: '' 就可以了.

三 . 处理less文件

1 . 安装处理 css 相关 loader

cnpm install --save-dev css-loader style-loader

css-loader让你能import css , style-loader能将css以style的形式插入

2 . 安装 less 相关

cnpm install --save-dev less less-loader

3 . 安装 postcsspostcss-cssnext 添加浏览器前缀

cnpm install --save-dev postcss-loader postcss-cssnext
项目根目录下创建 postcss.config.js 加入以下代码

module.exports = {
    plugins: [
        'postcss-cssnext': {}
    ]
}

我在这里尝试 autoprefixer 插件但是好像不管用,可能还依赖别的包.

4 . 配置webpack

webpack.config.js -> module -> rules 里添加配置
处理顺序从右到左 less -> postcss -> css -> style

{
    test: /\.less$/,
    use: ['style-loader', 'css-loader', 'postcss-loader', 'less-loader']
}

四 . 插件

1 . 生成HTML插件

安装插件cnpm install --save-dev html-webpack-plugin
配置 webpack.config.js

const htmlWebpackPlugin = require('html-webpack-plugin');
...
plugins: [
    new htmlWebpackPlugin({
        filename: "index.html",  //打包后的文件名
        template: path.join(__dirname , "./src/index.html")  //要打包文件的路径
    })
],

src 文件夹里创建一个 index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    </head>
    <body>
        <div id='root'></div>
    </body>
</html>

html-webpack-plugin用法全解
删除 bundle 文件夹下所有文件
重新运行 npm run build 看看效果吧

2 . 生成CSS插件

安装插件(目前必须有@next) cnpm install --save-dev extract-text-webpack-plugin@next
添加配置 webpack.config.js

const ExtractTextPlugin = require('extract-text-webpack-plugin');
...
module: {
    rules: [
        ...
        {
            test: /\.less$/,
            use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: ['css-loader', 'postcss-loader', 'less-loader']
            })
        }
    ]
},
plugins: [
    ...
    new ExtractTextPlugin({
        filename: 'index.css'
    }),
],

3 . 清理打包文件插件

上述代码所打出的包名称一直是一样的,很容易造成缓存问题
我们在 webpack.config.js 中做一下修改 outoup 下的 filename: 'bundle.js'filename: 'bundle.[hash:8].js'

plugins -> ExtractTextPlugin 下的 filename: 'index.css'filename: 'index.[hash:8].css'
缓存的问题解决了,但是我们每次生成的都是不同名字的文件 bundle 文件夹里的东西越来越多,我们需要一个插件来清理它.
安装插件 cnpm install --save-dev clean-webpack-plugin
修改 webpack.config.js

const CleanWebpackPlugin = require('clean-webpack-plugin');
...
plugins: [
    ...
    new CleanWebpackPlugin(['bundle'])
]

五 . 提取公共js

webpack.config.js 里添加

output: {
    ...
    chunkFilename: '[name].[chunkhash:8].js'
},
...
optimization: {
    splitChunks: {
        cacheGroups: {
            vendor: {
                test: /[\\/]node_modules[\\/]/,
                name: 'common',
                chunks: 'all'
            }
        }
    }
},

参考文章 webpack4 splitChunksPlugin && runtimeChunkPlugin 配置杂记

六 . webpack-dev-server配置

安装 webpack-dev-server

cnpm install --save-dev webpack-dev-server

webpack.config.js 添加配置

...
devServer: {
    contentBase: path.join(__dirname, 'bundle'),  //启动路径
    host:'localhost',  //域名
    port: 8018,  //端口号
}

执行命令 npx webpack-dev-server --config webpack.config.js
为了方便使用添加 package.json 中,加入 --color(颜色) --progress(进度) --hot(热加载)

"scripts": {
    "build": "npx webpack --config webpack.config.js",
    "start": "npx webpack-dev-server --config webpack.config.js --color --progress --hot"
 },

七 . 编译图片

cnpm install --save-dev url-loader file-loader

webpack.config.js -> rules增加配置:

{
   test: /\.(png|jpg|gif)$/,
   use: [{
       loader: 'url-loader',
       options: {
           limit: 8192  //8k一下的转义为base64
       }
   }]
}

八 . 安装vue-loader

cnpm install --save vue

cnpm install --save-dev vue-loader vue-style-loader vue-template-compiler vue-hot-reload-api

webpack.config.js -> rules增加配置:

{
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
        loaders: {
            css: ExtractTextPlugin.extract({
                fallback: "vue-style-loader",
                use: ['css-loader','postcss-loader']
            })
            less: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: ['css-loader', 'postcss-loader', 'less-loader']
            })
        }
    }
},

完成版:

//package.json
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "npx webpack-dev-server --config webpack.config.js --color --progress --hot",
    "build": "npx webpack --config webpack.config.js"
  },
  "author": "gadzan",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-loader": "^7.1.4",
    "babel-plugin-transform-runtime": "^6.23.0",
    "babel-polyfill": "^6.26.0",
    "babel-preset-env": "^1.7.0",
    "clean-webpack-plugin": "^0.1.19",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^1.1.11",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "less": "^3.0.4",
    "less-loader": "^4.1.0",
    "postcss-cssnext": "^3.1.0",
    "postcss-loader": "^2.1.5",
    "style-loader": "^0.21.0",
    "url-loader": "^1.0.1",
    "vue-hot-reload-api": "^2.3.0",
    "vue-html-loader": "^1.2.4",
    "vue-loader": "^14.2.2",
    "vue-style-loader": "^4.1.0",
    "vue-template-compiler": "^2.5.16",
    "webpack": "^4.8.1",
    "webpack-cli": "^2.1.3",
    "webpack-dev-server": "^3.1.4"
  },
  "dependencies": {
    "copy-webpack-plugin": "^4.5.1",
    "vue": "^2.5.16"
  }
}

//webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

const config = {
    mode: 'development',
    entry: {
        main: './src/main.js'
    },
    output: {
        path: path.join(__dirname, './dist'),
        //filename:'bundle.js',
        chunkFilename: '[name].[chunkhash:8].js'
    },
    resolve:{
        extensions:[".js",".json",".jsx",".css",'.vue']
    },
    module: {
        rules: [
            {
                test: /\.vue$/,
                loader: 'vue-loader'
            },
            {
                test: /\.js$/,
                use:{
                    loader:'babel-loader',
                    options:{
                        presets:['env'],
                        plugins:['transform-runtime']
                    }
                },
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: 'css-loader'
                })
            },
            {
                test:/\.less$/,
                use: ExtractTextPlugin.extract({
                    fallback: "style-loader",
                    use: ['css-loader', 'postcss-loader', 'less-loader']
                })
            },
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    limit: 10000,
                    name:'assets/images/[name].[hash:7].[ext]'
                }
            },
        ]
    },
    plugins: [
        new ExtractTextPlugin('main.css'),
        new HtmlWebpackPlugin({template:'./src/index.html'}),
        new webpack.HotModuleReplacementPlugin(),
        new CleanWebpackPlugin(['bundle'])
    ],
    optimization: {
        splitChunks: {
            cacheGroups: {
                vendor: {
                    test: /[\\/]node_modules[\\/]/,
                    name: 'common',
                    chunks: 'all'
                }
            }
        }
    },
    devServer:{
        historyApiFallback: true,
        noInfo: true,
        overlay: true,
        port:9000,
        hot:true,
        inline:true,
        open:true
    }
};

module.exports = config;

评论