├── .github
└── workflows
│ └── node.js.yml
├── .gitignore
├── ModelView_WallpaperEngine_template.html
├── ProcessControlPlugin.js
├── README.md
├── dist
└── .gitkeep
├── example
└── image_2020-06-22_21-38-48.png
├── imgs
└── show.png
├── index.html
├── index.js
├── lib
└── marmoset.js
├── model
├── scene.mview
└── test.mview
├── music
└── LaSoLa.mp3
├── outputDir
└── all.bundle.js
├── package-lock.json
├── package.json
├── wallper.config.js
└── webpack.config.js
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | name: Build and Deploy
2 | on:
3 | push:
4 | branches:
5 | - master
6 | jobs:
7 | build-and-deploy:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Checkout 🛎️
11 | uses: actions/checkout@v2
12 | with:
13 | persist-credentials: false
14 |
15 | - name: Install and Build 🔧
16 | run: |
17 | npm install
18 |
19 | npm run-script build
20 |
21 | - name: Deploy to GitHub Pages
22 | uses: JamesIves/github-pages-deploy-action@3.5.5
23 | with:
24 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
25 | BRANCH: gh-pages
26 | FOLDER: dist
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | .vscode
3 | node_modules
4 | dist/index.html
5 | outputDir/index.html
6 | model
--------------------------------------------------------------------------------
/ModelView_WallpaperEngine_template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= htmlWebpackPlugin.options.title %>
8 |
9 |
10 |
13 |
14 |
17 |
18 |
19 |
20 |
23 |
66 |
67 |
68 |
69 |
70 |
73 |
74 |
77 |
78 |
--------------------------------------------------------------------------------
/ProcessControlPlugin.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const path = require("path");
3 |
4 | let CustomPlugin = function(options) {
5 | options = options || {};
6 | this.options = options;
7 | };
8 |
9 | CustomPlugin.prototype.apply = function(compiler) {
10 | // 如果希望在生成的资源输出到output指定目录之前执行某个功能
11 | compiler.hooks.emit.tap("ProcessControl", () => {});
12 |
13 | // 编译完成之后
14 | compiler.hooks.done.tap("ProcessControl", () => {
15 | // 执行一次图片封装解析
16 | var sourceFile = path.join(__dirname, "outputDir/index.html");
17 | var destPath = path.join(__dirname, "dist", "index.html");
18 | var readStream = fs.createReadStream(sourceFile);
19 | var writeStream = fs.createWriteStream(destPath);
20 | readStream.pipe(writeStream);
21 | console.log("move done");
22 | try {
23 | fs.unlinkSync("outputDir/index.html");
24 | //file removed
25 | } catch (err) {
26 | console.error(err);
27 | }
28 | });
29 | };
30 |
31 | module.exports = CustomPlugin;
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # what's this
2 |
3 | it's teamplate export a single html with webpack,nodejs, make images to base64 to show,
4 | and with .mview model.
5 |
6 | 可以将图片和模型导出为完整html,配合wallperEngine 可做壁纸,使用ModelView_WallpaperEngine_templatee.html模版导出
7 |
8 | ## [model demo](https://github.com/ChenYCL/single-html/tree/wallpaper)
9 |
10 | # rules
11 |
12 | - imgs
13 | dir collect image
14 |
15 | 放置图片的文件夹,将会自动打包
16 |
17 | - model
18 | dir collect .mview etc
19 |
20 | 放置模型的文件夹,将会自动打包
21 |
22 | # use
23 |
24 | ```$javascript
25 | npm install
26 | npm run fix-memory-limit
27 | npm run build // normal
28 | npm run wallper // for wallper engine
29 |
30 | // export dist/index.html
31 | // 导出位置 dist/index.htl
32 |
33 |
34 | ```
35 |
36 | global variable on window
37 |
38 | [filename]\_model - model object,if imgs dir have scene.mview
39 |
40 | 模型变量 文件名_model
41 |
42 | eg. scene_model
43 |
44 | [filename]\_img - image object,if imgs dir have show.png
45 |
46 | 图片变量 文件名_img
47 |
48 | eg. show_img
49 |
50 | # Preview
51 |
52 | 
53 |
54 | ## wallpaper_engine
55 |
56 | 
57 |
--------------------------------------------------------------------------------
/dist/.gitkeep:
--------------------------------------------------------------------------------
1 | # Ignore everything in this directory
2 | *
3 | # Except this file !.gitkeep
--------------------------------------------------------------------------------
/example/image_2020-06-22_21-38-48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/example/image_2020-06-22_21-38-48.png
--------------------------------------------------------------------------------
/imgs/show.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/imgs/show.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= htmlWebpackPlugin.options.title %>
8 |
9 |
10 |
13 |
14 |
17 |
20 |
23 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | desc here...
77 | first pic
78 |
79 |
82 | second pic
83 |
84 |
85 |
96 |
97 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var marmoset = require("./lib/marmoset");
--------------------------------------------------------------------------------
/model/scene.mview:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/model/scene.mview
--------------------------------------------------------------------------------
/model/test.mview:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/model/test.mview
--------------------------------------------------------------------------------
/music/LaSoLa.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ChenYCL/single-html/052186f1a5be146774b28999f256ff3b8fff3785/music/LaSoLa.mp3
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-base64",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --config webpack.config.js",
8 | "wallper": "webpack --config wallper.config.js",
9 | "fix-memory-limit": "cross-env LIMIT=8096 increase-memory-limit"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "copy-webpack-plugin": "^6.0.2",
15 | "fs-extra": "^9.0.1",
16 | "webpack-parallel-uglify-plugin": "^1.1.2"
17 | },
18 | "devDependencies": {
19 | "clean-webpack-plugin": "^3.0.0",
20 | "cross-env": "^7.0.2",
21 | "css-loader": "^3.6.0",
22 | "extract-loader": "^5.1.0",
23 | "file-loader": "^6.0.0",
24 | "html-loader": "^1.1.0",
25 | "html-webpack-plugin": "^4.3.0",
26 | "increase-memory-limit": "^1.0.7",
27 | "raw-loader": "^4.0.1",
28 | "style-loader": "^1.2.1",
29 | "url-loader": "^4.1.0",
30 | "webpack": "^4.43.0",
31 | "webpack-cli": "^3.3.12"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/wallper.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); // installed via npm
2 | const path = require('path');
3 | const fs = require('fs');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 | const ProcessControlPlugin = require('./ProcessControlPlugin');
6 | const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
7 | const CopyPlugin = require('copy-webpack-plugin');
8 |
9 | console.log('Build process is starting');
10 | // try {
11 | // fs.unlinkSync('outputDir/index.html')
12 | // //file removed
13 | // } catch(err) {
14 | // console.error(err)
15 | // }
16 |
17 | let modelOBJ = {};
18 | let modelArr = fs.readdirSync('./model');
19 | modelArr.map((filename, idx) => {
20 | // 模型转 base64
21 | if(filename === 'test'){return false};
22 | var buff = fs.readFileSync(`./model/${filename}`);
23 | var base64data = buff.toString('base64');
24 | modelOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
25 | //console.log(base64data);
26 | });
27 | console.log('\n模型转换完毕...\n');
28 |
29 |
30 | let mp3OBJ = {};
31 | let mp3Arr = fs.readdirSync('./music');
32 | mp3Arr.map((filename, idx) => {
33 | // 模型转 base64
34 | var buff = fs.readFileSync(`./music/${filename}`);
35 | var base64data = buff.toString('base64');
36 | mp3OBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
37 | // console.log(base64data);
38 | });
39 | console.log('\n音频转换完毕...\n');
40 |
41 | // image -> base64
42 | let imgOBJ = {};
43 | let imgArr = fs.readdirSync('./imgs');
44 | imgArr.map((filename, idx) => {
45 | // 模型转 base64
46 | var buff = fs.readFileSync(`./imgs/${filename}`);
47 | var base64data = Buffer.from(buff, 'binary').toString('base64');
48 | imgOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
49 | //console.log(base64data);
50 | });
51 | console.log('\n图片转换完毕...开始打包\n');
52 |
53 | module.exports = {
54 | entry: './index.js',
55 | output: {
56 | path: path.resolve(__dirname, 'outputDir'),
57 | filename: 'all.bundle.js',
58 | },
59 | mode: 'production',
60 | module: {
61 | rules: [
62 | {
63 | test: /\.(png|jpg|gif|jpeg|svg)$/i,
64 | use: [
65 | {
66 | loader: 'url-loader',
67 | options: {
68 | limit: 99999999999999999,
69 | name: 'images/[name]-[hash:8].[ext]',
70 | },
71 | },
72 | ],
73 | },
74 | // {
75 | // test: /\.js$/i,
76 | // loader: "file-loader",
77 | // },
78 | { test: /\.txt$/, use: 'raw-loader' },
79 | { test: /\.css$/, use: 'css-loader', exclude: /node_modules/ },
80 | { test: /\.css$/, use: 'style-loader', exclude: /node_modules/ },
81 | ],
82 | },
83 | plugins: [
84 | new ProcessControlPlugin(),
85 | // new ParallelUglifyPlugin({
86 | // cacheDir: "./node_modules/cache/",
87 | // uglifyJS: {
88 | // output: {
89 | // comments: false,
90 | // },
91 | // warnings: false,
92 | // },
93 | // }),
94 |
95 | new HtmlWebpackPlugin({
96 | template: './ModelView_WallpaperEngine_template.html',
97 | filename: 'index.html',
98 | title: "it's a template1",
99 | inject: false,
100 | templateParameters: {
101 | model_base64_data: (() => {
102 | let script = '';
103 | for (key in modelOBJ) {
104 | script += `var ${key}_model = "${modelOBJ[key]}";\n`;
105 | }
106 | return script;
107 | })(),
108 | images_base64_data: (() => {
109 | let script = '';
110 | for (key in imgOBJ) {
111 | script += `var ${key}_img = "${imgOBJ[key]}";\n`;
112 | }
113 | return script;
114 | })(),
115 | mp3_base64_data: (() => {
116 | let script = '';
117 | for (key in mp3OBJ) {
118 | script += `var ${key}_mp3 = "${mp3OBJ[key]}";\n`;
119 | }
120 | return script;
121 | })(),
122 | myscript: (() => {
123 | const d = fs.readFileSync(
124 | 'outputDir/all.bundle.js',
125 | async (err, data) => {
126 | return data;
127 | }
128 | );
129 | return d;
130 | })(),
131 | },
132 | // minify: {
133 | // //删除html空格
134 | // collapseWhitespace: true,
135 | // //尽可能使用直接Unicode字符
136 | // decodeEntities: true,
137 | // //指定最大行长度。压缩输出将在有效的HTML分割点按换行符分割
138 | // // maxLineLength:30,
139 | // //在样式元素和样式属性中缩小CSS(使用clean-css)
140 | // minifyCSS: true,
141 | // //缩小脚本元素和事件属性中的JavaScript(使用UglifyJS)
142 | // minifyJS: true,
143 | // //尽可能删除属性周围的引号
144 | // removeAttributeQuotes: true,
145 | // //删除内容为空的属性
146 | // removeEmptyAttributes: true,
147 | // },
148 | }),
149 |
150 | // new CopyPlugin({
151 | // patterns: [
152 | // {from: './outputDir/index.html', to: './dist/'}
153 | // ]
154 | // }),
155 | ],
156 | };
157 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); // installed via npm
2 | const path = require('path');
3 | const fs = require('fs');
4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin');
5 | const ProcessControlPlugin = require('./ProcessControlPlugin');
6 | const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
7 | const CopyPlugin = require('copy-webpack-plugin');
8 |
9 | console.log('Build process is starting');
10 | // try {
11 | // fs.unlinkSync('outputDir/index.html')
12 | // //file removed
13 | // } catch(err) {
14 | // console.error(err)
15 | // }
16 |
17 | let modelOBJ = {};
18 | let modelArr = fs.readdirSync('./model');
19 | modelArr.map((filename, idx) => {
20 | // 模型转 base64
21 | var buff = fs.readFileSync(`./model/${filename}`);
22 | var base64data = buff.toString('base64');
23 | modelOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
24 | //console.log(base64data);
25 | });
26 | console.log('\n模型转换完毕...\n');
27 |
28 |
29 | let mp3OBJ = {};
30 | let mp3Arr = fs.readdirSync('./music');
31 | mp3Arr.map((filename, idx) => {
32 | // 模型转 base64
33 | var buff = fs.readFileSync(`./music/${filename}`);
34 | var base64data = buff.toString('base64');
35 | mp3OBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
36 | // console.log(base64data);
37 | });
38 | console.log('\n音频转换完毕...\n');
39 |
40 | // image -> base64
41 | let imgOBJ = {};
42 | let imgArr = fs.readdirSync('./imgs');
43 | imgArr.map((filename, idx) => {
44 | // 模型转 base64
45 | var buff = fs.readFileSync(`./imgs/${filename}`);
46 | var base64data = Buffer.from(buff, 'binary').toString('base64');
47 | imgOBJ[filename.substr(0, filename.lastIndexOf('.'))] = base64data;
48 | //console.log(base64data);
49 | });
50 | console.log('\n图片转换完毕...开始打包\n');
51 |
52 | module.exports = {
53 | entry: './index.js',
54 | output: {
55 | path: path.resolve(__dirname, 'outputDir'),
56 | filename: 'all.bundle.js',
57 | },
58 | mode: 'production',
59 | module: {
60 | rules: [
61 | {
62 | test: /\.(png|jpg|gif|jpeg|svg)$/i,
63 | use: [
64 | {
65 | loader: 'url-loader',
66 | options: {
67 | limit: 99999999999999999,
68 | name: 'images/[name]-[hash:8].[ext]',
69 | },
70 | },
71 | ],
72 | },
73 | // {
74 | // test: /\.js$/i,
75 | // loader: "file-loader",
76 | // },
77 | { test: /\.txt$/, use: 'raw-loader' },
78 | { test: /\.css$/, use: 'css-loader', exclude: /node_modules/ },
79 | { test: /\.css$/, use: 'style-loader', exclude: /node_modules/ },
80 | ],
81 | },
82 | plugins: [
83 | new ProcessControlPlugin(),
84 | // new ParallelUglifyPlugin({
85 | // cacheDir: "./node_modules/cache/",
86 | // uglifyJS: {
87 | // output: {
88 | // comments: false,
89 | // },
90 | // warnings: false,
91 | // },
92 | // }),
93 |
94 | new HtmlWebpackPlugin({
95 | template: './index.html',
96 | filename: 'index.html',
97 | title: "it's a template1",
98 | inject: false,
99 | templateParameters: {
100 | // 模型注入
101 | model_base64_data: (() => {
102 | let script = '';
103 | for (key in modelOBJ) {
104 | script += `var ${key}_model = "${modelOBJ[key]}";\n`;
105 | }
106 | return script;
107 | })(),
108 | // 图片注入
109 | images_base64_data: (() => {
110 | let script = '';
111 | for (key in imgOBJ) {
112 | script += `var ${key}_img = "${imgOBJ[key]}";\n`;
113 | }
114 | return script;
115 | })(),
116 | // 音频注入
117 | mp3_base64_data: (() => {
118 | let script = '';
119 | for (key in mp3OBJ) {
120 | script += `var ${key}_mp3 = "${mp3OBJ[key]}";\n`;
121 | }
122 | return script;
123 | })(),
124 | myscript: (() => {
125 | const d = fs.readFileSync(
126 | 'outputDir/all.bundle.js',
127 | async (err, data) => {
128 | return data;
129 | }
130 | );
131 | return d;
132 | })(),
133 | },
134 | // minify: {
135 | // //删除html空格
136 | // collapseWhitespace: true,
137 | // //尽可能使用直接Unicode字符
138 | // decodeEntities: true,
139 | // //指定最大行长度。压缩输出将在有效的HTML分割点按换行符分割
140 | // // maxLineLength:30,
141 | // //在样式元素和样式属性中缩小CSS(使用clean-css)
142 | // minifyCSS: true,
143 | // //缩小脚本元素和事件属性中的JavaScript(使用UglifyJS)
144 | // minifyJS: true,
145 | // //尽可能删除属性周围的引号
146 | // removeAttributeQuotes: true,
147 | // //删除内容为空的属性
148 | // removeEmptyAttributes: true,
149 | // },
150 | }),
151 |
152 | // new CopyPlugin({
153 | // patterns: [
154 | // {from: './outputDir/index.html', to: './dist/'}
155 | // ]
156 | // }),
157 | ],
158 | };
159 |
--------------------------------------------------------------------------------