轻应用项目工程脚手架:从零到一搭建详细攻略

本文主要跟大家分享一下如何使用webpack4来一步一步搭建自己的项目框架。如果没接触过webpack,或者不是很了解,建议在阅读本文之前先去webpack 中文网了解一下基本概念、核心理念 入口(entry)、输出(output)、loader、插件(plugins)等知识。

主要功能:

1、支持VUE
2、支持React
3、支持less、scss
4、图片压缩,css分离
5、px转rem
6、ES6
7、打包后自动压缩zip文件
8、支持本地调试
9、支持本地mock数据服务
复制代码

1、首先谈一谈我使用webpack搭建项目框架的目的

我负责的主要是用于各种节日活动的H5项目,项目比较独立,周期比较短,之前每个项目一个开发人员就可以搞定,但是随着公司发展,现在做的活动越来越复杂,每个项目需要的人员也随之增加,但是大家的技术栈不一样,有人用zepto.js,有人用vue,有人用react,有人习惯原始的css,有人喜欢less、scss,在项目中,为了让大家都还使用自己擅长的技术栈来开发,带着这样的目的,从而从0到1,慢慢搭建起自己的项目框架,目前框架已生成脚手架,发布到npm,有兴趣的同学可以安装体验一下。

使用步骤:

1、安装脚手架,执行 npm install light-app-cli -g
2、创建项目,执行light-app-cli <项目名称>
3、详见 [GitHub地址](https://github.com/hanhan3682523/light-app-cli)
复制代码

2、从0到1的过程

环境要求:

1、node >= 10.5.0,[node下载地址]: https://nodejs.org/en/download/
2、webpack >=4.16.0,安装:npm install -g webpack
3、框架目录结构预览

搭建流程:

1、目录及文件说明
2、配置入口(entry)
3、配置出口(output)
4、配置loader
5、配置插件(plugins)
6、开发环境配置devSever
复制代码

1、目录及文件说明

|- build
    -- webpack.base.conf.js--开发和打包用到的公用配置项,通过webpack-merge 分别使用
    -- webpack.build.config.js--打包配置
    -- webpack.dev.config.js--开发配置,生成本地服务,设置访问域名、热替换、代理、端口等信息
    -- webpack.plugins.js--配置webpack插件
    -- webpack.rules.js--配置webpack loader,进行文件处理
|- config
    -- index.js--本地服务域名、端口等配置
|- dist
|- mock
    -- data.js--设置mock接口数据
    -- server.js--本地mock服务
|- src
    |- assets
    |- css
    |- image
    |- js
    -- index.html
|- zip
|- .babelc 
|-  package.json
|-  postcss.config.js
|-  tsconfig.json
复制代码

2、配置入口(entry)

项目为多页面应用,会涉及到多个入口,所以我们进行约定,所有入口文件统一放到src目录下的js文件夹中,利用globby模块,读取js文件夹下的所有js名称(不包括子文件夹),从而返回一个入口(entry)对象。

//读取文件
const glob = require('globby');

let entryConfig = (function() {
    let _config = {};
    //选择js目录下的文件,不包含common中的js作为入口
    const fileList = glob.sync(['./src/js/*.*']);
    console.info('tag', fileList);
    if (fileList && fileList.length > 0) {
        for (let i = 0; i < fileList.length; i++) {
            _config[fileList[i].match(/([^\/]+)(?=\.)/ig)[0]] = fileList[i];
        }
    }
    return _config;
})();

//入口
entry: entryConfig,
复制代码

3、配置出口(output)

在filename中添加了hash命名,目的是为了防止cdn缓存、浏览器缓存,每次打包,都会对静态资源重新命名,这样修改发布后,只需要推html的缓存即可。

//出口
output: {
    filename: 'js/[name][hash].js',
    path: config.build.assetsRoot,
    publicPath: process.env.NODE_ENV === 'production' ?
        config.build.assetsPublicPath :
        config.dev.assetsPublicPath
},
复制代码

4、配置loader

项目中文件类型较多,每种文件类型都有专门的loader进行处理,涉及的loader比较多,所以把loader统一放到webpack.rules.js中进行管理,方便维护和扩展。

//loader,rulesConfig内容详见下面webpack.rules.js
module: {
    rules: rulesConfig
},

//webpack.rules.js 中内容
/*
作者:飘落的枫叶
说明:配置webpack打包loader加载器
日期:2018.6.1
*/
const path = require('path');
const extractTextPlugin = require("extract-text-webpack-plugin");

function resolve(dir) {
    return path.join(__dirname, '..', dir)
}

module.exports = [{
    test: /\.vue$/,
    use: {
        loader: 'vue-loader'
    },
    //加快搜索速度
    exclude: resolve('node_modules'),
}, {
    test: /\.ts$/,
    use: {
        loader: 'ts-loader'
    },
    //加快搜索速度
    exclude: resolve('node_modules'),
}, {
    test: /\.js$/,
    use: {
        loader: 'babel-loader',
        options: {
            presets: ['env', 'react'],
            plugins: ['transform-runtime'],
            cacheDirectory: true
        }
    },
    exclude: resolve('node_modules'),
}, {
    test: /\.css$/,
    use: extractTextPlugin.extract({
        fallback: "style-loader",
        use: ["css-loader", "postcss-loader"],
        // css中的基础路径
        publicPath: "../"
    })
}, {
    test: /\.((woff2?|svg)(\?v=[0-9]\.[0-9]\.[0-9]))|(woff2?|svg|jpe?g|png|gif|ico)$/,
    use: [{
        loader: 'url-loader',
        options: {
            limit: 8192, //设置转换成base64的大小
            name: '[name][hash:8].[ext]',
            outputPath: 'image/'
        }
    }],
    //只命中src目录中的文件,加快搜索速度
    include: resolve('src')
}, {
    test: /\.(html)$/,
    use: {
        loader: 'html-loader'
    },
    //只命中src目录中的文件,加快搜索速度
    include: resolve('src')
}, {
    test: /\.less$/,
    use: extractTextPlugin.extract({
        fallback: "style-loader",
        use: ["css-loader", "postcss-loader", "less-loader"],
        // css中的基础路径
        publicPath: "../"
    }),
    //只命中src目录中的文件,加快搜索速度
    include: resolve('src')
}, {
    test: /\.(scss|sass)$/,
    // 分离的写法
    use: extractTextPlugin.extract({
        fallback: "style-loader",
        use: ["css-loader", "postcss-loader", "sass-loader"],
        // css中的基础路径
        publicPath: "../"
    }),
    //只命中src目录中的文件,加快搜索速度
    include: resolve('src')
}];
复制代码

5、配置插件(plugins)

插件可以自定义webpack的构建过程,webpack本身也内置了一些插件。同loader一样,为了便于管理,我们把插件统一放到webpack.plugins.js中进行管理,这里面使用插件主要用于分离css文件,处理vue文件,以及打包后自动压缩zip文件等。

//插件,pluginsConfig内容见下面webpack.plugins.js
plugins: pluginsConfig

//webpack.plugins.js
/*
作者:飘落的枫叶
说明:配置webpack打包插件
日期:2018.6.1
*/
//配置文件
const config = require('../config/index')
//路徑
const path = require('path');
// html模板
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 清除目录等
const CleanWebpackPlugin = require('clean-webpack-plugin');
// 分离css
const extractTextPlugin = require("extract-text-webpack-plugin");
//静态资源输出
const copyWebpackPlugin = require("copy-webpack-plugin");
//css压缩
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
//vue插件
const VueLoaderPlugin = require('vue-loader/lib/plugin');
//打包文件
const FileManagerPlugin = require('filemanager-webpack-plugin');


//读取文件
var glob = require('globby');
//webpack
const webpack = require('webpack');

var pluginsConfig = [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin(),
    // 调用之前先清除
    new CleanWebpackPlugin(['dist', 'zip'], {
        root: path.resolve(__dirname, "..")
    }),
    //vue插件
    new VueLoaderPlugin(),
    //静态资源输出
    new copyWebpackPlugin([{
        from: path.resolve(__dirname, "../src/assets"),
        to: './assets'
    }]),
    // 分离css插件参数为提取出去的路径
    new extractTextPlugin({
        filename: 'style/[name][hash].css',
    }),
    //css进行压缩
    new OptimizeCssAssetsPlugin({
        //assetNameRegExp: /\.style\.css$/g,
        cssProcessor: require('cssnano'),
        cssProcessorOptions: {
            discardComments: {
                removeAll: true
            }
        },
        canPrint: true
    })
];

(function() {
    const fileList = glob.sync(['./src/*.html']);
    if (fileList && fileList.length > 0) {
        for (var i = 0; i < fileList.length; i++) {
            pluginsConfig.push(
                new HtmlWebpackPlugin({
                    template: fileList[i],
                    filename: fileList[i].match(/([^\/]+)(?=\.)/ig)[0] + '.html',
                    chunks: [fileList[i].match(/([^\/]+)(?=\.)/ig)[0]],
                    hash: false, //引入的文件设置hash值
                })
            );
        }
    }
})();

//自动压缩dist 到zip文件
//环境判断
if (process.env && process.env.NODE_ENV && process.env.NODE_ENV.trim() === "production" && config.build.zipName) {
    // 调用之前先清除
    pluginsConfig.push(new CleanWebpackPlugin(['zip']));
    let _zipfilename = config.build.zipName;
    pluginsConfig.push(new FileManagerPlugin({
        onEnd: {
            //c
            mkdir: ['./zip', './tempzip/' + _zipfilename],
            copy: [{
                source: './dist',
                destination: './tempzip/' + _zipfilename
            }, ],
            archive: [{
                source: './tempzip/',
                destination: './zip/' + _zipfilename + '.zip'
            }],
            delete: [
                './tempzip/'
            ]
        }
    }));
}

module.exports = pluginsConfig;
复制代码

6、开发环境配置devSever

项目开发过程中,为了便于开发调试,我们需要设置本地开发环境,起http服务,支持自动打开浏览器,文件修改后自动刷新或热更新页面,https,接口请求代理等功能。

const config = require('../config/index')
const common = require('./webpack.base.conf');
const merge = require('webpack-merge');

module.exports = merge(common, {
    mode: 'development',
    //生成map文件,供调试
    devtool: 'eval-source-map',
    //监听文件更新,在文件发生变化时重新编译,使用 DevServer 时,监听模式默认是开启的。
    watch: true,
    //控制监听模式
    watchOptions: {
        // 不监听的文件或文件夹,支持正则匹配
        ignored: /node_modules/,
        // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高,默认为 300ms 
        aggregateTimeout: 300,
        // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的,默认每秒轮询1000次
        poll: 1000
    },
    //http服务设置
    devServer: {
        //代理
        proxy: {
            '/api': 'http://127.0.0.1:9001',
            changeOrigin: true
        },
        //运行目录
        contentBase: './',
        //一切服务都启用gzip 压缩:
        compress: true,
        //端口号
        port: config.dev.port || '8080',
        //自动打开浏览器
        open: true,
        //模块热替换
        hot: true,
        //页面自动刷新
        inline: true,
        //打开的页面
        openPage: '',
        //host:'0.0.0.0'--别人可以访问
        host: config.dev.host || 'hxj.com',
        //支持https
        https:  config.dev.https,
    }
});
复制代码

源码地址

项目框架GitHub源码地址

CLI脚手架GitHub源码地址

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值