├── .eslintignore
├── example
├── remax
│ ├── .eslintignore
│ ├── src
│ │ ├── pages
│ │ │ ├── Index
│ │ │ │ ├── index.module.sass
│ │ │ │ ├── gua.jpg
│ │ │ │ ├── index.config.js
│ │ │ │ └── index.js
│ │ │ ├── Miao.config.js
│ │ │ └── Miao.js
│ │ ├── test.js
│ │ ├── app.sass
│ │ ├── app.js
│ │ └── app.config.js
│ ├── .eslintrc.js
│ ├── .babelrc.js
│ ├── package.json
│ └── build
│ │ └── webpack.config.js
└── simple
│ ├── src
│ ├── pages
│ │ ├── Miao.pug
│ │ ├── Index
│ │ │ ├── index.pug
│ │ │ ├── index.module.sass
│ │ │ ├── index.config.js
│ │ │ └── index.js
│ │ ├── Miao.js
│ │ └── Miao.config.js
│ ├── test.js
│ ├── app.sass
│ ├── app.js
│ └── app.config.js
│ ├── .babelrc.js
│ ├── package.json
│ └── build
│ └── webpack.config.js
├── packages
├── core
│ ├── .babelrc.js
│ ├── src
│ │ ├── remax
│ │ │ ├── adapter
│ │ │ │ └── wechat
│ │ │ │ │ ├── hostComponents
│ │ │ │ │ ├── picker-view-column.js
│ │ │ │ │ ├── label.js
│ │ │ │ │ ├── open-data.js
│ │ │ │ │ ├── web-view.js
│ │ │ │ │ ├── swiper-item.js
│ │ │ │ │ ├── official-account.js
│ │ │ │ │ ├── checkbox-group.js
│ │ │ │ │ ├── cover-view.js
│ │ │ │ │ ├── radio-group.js
│ │ │ │ │ ├── icon.js
│ │ │ │ │ ├── functional-page-navigator.js
│ │ │ │ │ ├── movable-area.js
│ │ │ │ │ ├── ad.js
│ │ │ │ │ ├── radio.js
│ │ │ │ │ ├── text.js
│ │ │ │ │ ├── cover-image.js
│ │ │ │ │ ├── checkbox.js
│ │ │ │ │ ├── form.js
│ │ │ │ │ ├── contact-button.js
│ │ │ │ │ ├── switch.js
│ │ │ │ │ ├── image.js
│ │ │ │ │ ├── camera.js
│ │ │ │ │ ├── rich-text.js
│ │ │ │ │ ├── editor.js
│ │ │ │ │ ├── picker-view.js
│ │ │ │ │ ├── audio.js
│ │ │ │ │ ├── picker.js
│ │ │ │ │ ├── canvas.js
│ │ │ │ │ ├── progress.js
│ │ │ │ │ ├── navigator.js
│ │ │ │ │ ├── slider.js
│ │ │ │ │ ├── movable-view.js
│ │ │ │ │ ├── live-player.js
│ │ │ │ │ ├── scroll-view.js
│ │ │ │ │ ├── view.js
│ │ │ │ │ ├── swiper.js
│ │ │ │ │ ├── input.js
│ │ │ │ │ ├── live-pusher.js
│ │ │ │ │ ├── button.js
│ │ │ │ │ ├── textarea.js
│ │ │ │ │ ├── map.js
│ │ │ │ │ └── video.js
│ │ │ │ │ └── index.js
│ │ │ ├── BabelRemaxPagePlugin.js
│ │ │ ├── BabelRemaxAppPlugin.js
│ │ │ ├── applyRemaxAssets.js
│ │ │ ├── BabelRemaxComponentPlugin.js
│ │ │ └── applyEntryDecoration.js
│ │ ├── constants.js
│ │ ├── ensureRequire.js
│ │ ├── utils.js
│ │ ├── applyStaticAssetDecoration.js
│ │ ├── applyChunks.js
│ │ ├── applySplitting.js
│ │ ├── applyChunkAssets.js
│ │ ├── applyChunkDecorations.js
│ │ ├── index.js
│ │ ├── injectEnv.js
│ │ └── getEntryMap.js
│ ├── __tests__
│ │ └── core.test.js
│ ├── templates
│ │ ├── page.ejs
│ │ ├── component.ejs
│ │ ├── base.ejs
│ │ └── helper.js
│ ├── package.json
│ └── README.md
└── mina-assets-loader
│ ├── .babelrc.js
│ ├── src
│ ├── utils.js
│ └── index.js
│ ├── package.json
│ └── README.md
├── lerna.json
├── .babelrc.js
├── .eslintrc.js
├── .gitignore
├── package.json
└── README.md
/.eslintignore:
--------------------------------------------------------------------------------
1 | dist/*
2 |
--------------------------------------------------------------------------------
/example/remax/.eslintignore:
--------------------------------------------------------------------------------
1 | dist
2 | node_modules
--------------------------------------------------------------------------------
/example/simple/src/pages/Miao.pug:
--------------------------------------------------------------------------------
1 | view {{ test }}
--------------------------------------------------------------------------------
/example/simple/src/pages/Index/index.pug:
--------------------------------------------------------------------------------
1 | view {{ foo }}
2 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Index/index.module.sass:
--------------------------------------------------------------------------------
1 | .Test
2 | display: block
--------------------------------------------------------------------------------
/packages/core/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('../../.babelrc')
2 |
--------------------------------------------------------------------------------
/example/remax/src/test.js:
--------------------------------------------------------------------------------
1 | import './app.sass'
2 | export default 'test'
3 |
--------------------------------------------------------------------------------
/example/simple/src/pages/Index/index.module.sass:
--------------------------------------------------------------------------------
1 | .Test
2 | display: block
--------------------------------------------------------------------------------
/example/simple/src/test.js:
--------------------------------------------------------------------------------
1 | import './app.sass'
2 | export default 'test'
3 |
--------------------------------------------------------------------------------
/example/remax/src/app.sass:
--------------------------------------------------------------------------------
1 | view
2 | display: block
3 | box-sizing: border-box
4 |
--------------------------------------------------------------------------------
/example/simple/src/app.sass:
--------------------------------------------------------------------------------
1 | view
2 | display: block
3 | box-sizing: border-box
4 |
--------------------------------------------------------------------------------
/packages/mina-assets-loader/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = require('../../.babelrc')
2 |
--------------------------------------------------------------------------------
/lerna.json:
--------------------------------------------------------------------------------
1 | {
2 | "packages": [
3 | "packages/*"
4 | ],
5 | "version": "0.0.0"
6 | }
7 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/picker-view-column.js:
--------------------------------------------------------------------------------
1 | export const props = [];
2 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/label.js:
--------------------------------------------------------------------------------
1 | export const props = ['id', 'class', 'style', 'for', 'animation']
2 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Index/gua.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/krhougs/mina-webpack-plugin/HEAD/example/remax/src/pages/Index/gua.jpg
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/open-data.js:
--------------------------------------------------------------------------------
1 | export const props = ['type', 'open-gid', 'lang', 'animation'];
2 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/web-view.js:
--------------------------------------------------------------------------------
1 | export const props = ['src', 'bindmessage', 'bindload', 'binderror'];
2 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/swiper-item.js:
--------------------------------------------------------------------------------
1 | export const props = ['key', 'id', 'class', 'style', 'item-id', 'animation'];
2 |
--------------------------------------------------------------------------------
/packages/core/__tests__/core.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const core = require('..');
4 |
5 | describe('core', () => {
6 | it('needs tests');
7 | });
8 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/official-account.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'bindload',
3 | 'binderror',
4 | 'animation'
5 | ]
6 |
--------------------------------------------------------------------------------
/example/remax/src/app.js:
--------------------------------------------------------------------------------
1 | import test from './test'
2 |
3 | import './app.sass'
4 |
5 | App({
6 | onShow () {
7 | console.log(test)
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/example/simple/src/app.js:
--------------------------------------------------------------------------------
1 | import test from './test'
2 |
3 | import './app.sass'
4 |
5 | App({
6 | onShow () {
7 | console.log(test)
8 | }
9 | })
10 |
--------------------------------------------------------------------------------
/example/simple/src/pages/Miao.js:
--------------------------------------------------------------------------------
1 | import test from '../test'
2 |
3 | import './Miao.pug'
4 |
5 | Page({
6 | data: {
7 | test,
8 | 114514: 1919810
9 | }
10 | })
11 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/checkbox-group.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'name',
6 | 'bindchange',
7 | 'animation'
8 | ]
9 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/cover-view.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'scroll-top',
6 | 'bindtap',
7 | 'animation'
8 | ]
9 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/radio-group.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'bindchange',
6 | 'name',
7 | 'animation'
8 | ]
9 |
--------------------------------------------------------------------------------
/packages/core/templates/page.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/example/remax/src/app.config.js:
--------------------------------------------------------------------------------
1 | export default function ({
2 | setRoute
3 | }) {
4 | setRoute({
5 | index: 'pages/Index',
6 | miao: 'pages/Miao'
7 | })
8 | return {}
9 | }
10 |
--------------------------------------------------------------------------------
/example/simple/src/app.config.js:
--------------------------------------------------------------------------------
1 | export default function ({
2 | setRoute
3 | }) {
4 | setRoute({
5 | index: 'pages/Index',
6 | miao: 'pages/Miao'
7 | })
8 | return {}
9 | }
10 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/icon.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'type',
6 | 'size',
7 | 'color',
8 | 'animation'
9 | ]
10 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/functional-page-navigator.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'version',
3 | 'name',
4 | 'args',
5 | 'bindsuccess',
6 | 'bindfail',
7 | 'animation'
8 | ]
9 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/movable-area.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'class',
3 | 'style',
4 | 'width',
5 | 'height',
6 | 'id',
7 | 'scale-area',
8 | 'animation'
9 | ]
10 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/ad.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'unit-id',
3 | 'ad-type',
4 | 'ad-intervals',
5 | 'bindload',
6 | 'binderror',
7 | 'bindclose',
8 | 'animation'
9 | ]
10 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/radio.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'value',
6 | 'checked',
7 | 'disabled',
8 | 'color',
9 | 'animation'
10 | ]
11 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/text.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'selectable',
6 | 'space',
7 | 'decode',
8 | 'bindtap',
9 | 'animation'
10 | ]
11 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/cover-image.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'src',
6 | 'bindload',
7 | 'binderror',
8 | 'bindtap',
9 | 'animation'
10 | ]
11 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Miao.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | navigationBarTitleText: ' ',
3 | navigationBarBackgroundColor: '#FFFFFF',
4 | backgroundTextStyle: 'light',
5 | navigationBarTextStyle: 'black'
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/example/simple/src/pages/Miao.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | navigationBarTitleText: ' ',
3 | navigationBarBackgroundColor: '#FFFFFF',
4 | backgroundTextStyle: 'light',
5 | navigationBarTextStyle: 'black'
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/checkbox.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'value',
6 | 'checked',
7 | 'disabled',
8 | 'bindchange',
9 | 'color',
10 | 'animation'
11 | ]
12 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/form.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'report-submit',
6 | 'bindsubmit',
7 | 'bindreset',
8 | 'report-submit-timeout',
9 | 'animation'
10 | ]
11 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Index/index.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | navigationBarTitleText: ' ',
3 | navigationBarBackgroundColor: '#FFFFFF',
4 | backgroundTextStyle: 'light',
5 | navigationBarTextStyle: 'black'
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/example/simple/src/pages/Index/index.config.js:
--------------------------------------------------------------------------------
1 | const config = {
2 | navigationBarTitleText: ' ',
3 | navigationBarBackgroundColor: '#FFFFFF',
4 | backgroundTextStyle: 'light',
5 | navigationBarTextStyle: 'black'
6 | }
7 |
8 | export default config
9 |
--------------------------------------------------------------------------------
/example/simple/src/pages/Index/index.js:
--------------------------------------------------------------------------------
1 | import test from '../../test'
2 |
3 | import './index.pug'
4 | import style from './index.module.sass'
5 |
6 | console.log(style)
7 |
8 | Page({
9 | data: {
10 | foo: 'bar',
11 | test
12 | }
13 | })
14 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/contact-button.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'class',
3 | 'style',
4 | 'tnt-inst-id',
5 | 'scene',
6 | 'size',
7 | 'color',
8 | 'icon',
9 | 'alipay-card-no',
10 | 'animation'
11 | ]
12 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/switch.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'name',
6 | 'checked',
7 | 'disabled',
8 | 'color',
9 | 'bindchange',
10 | 'controlled',
11 | 'type',
12 | 'animation'
13 | ]
14 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/image.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'src',
4 | 'mode',
5 | 'class',
6 | 'style',
7 | 'lazy-load',
8 | 'bindload',
9 | 'binderror',
10 | 'bindtap',
11 | 'show-menu-by-longpress',
12 | 'animation'
13 | ]
14 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/camera.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'mode',
6 | 'device-position',
7 | 'flash',
8 | 'frame-size',
9 | 'bindstop',
10 | 'binderror',
11 | 'bindinitdone',
12 | 'bindscancode',
13 | 'animation'
14 | ]
15 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/rich-text.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'nodes',
6 | 'onTap',
7 | 'space',
8 | 'bindtouchstart',
9 | 'bindtouchmove',
10 | 'bindtouchend',
11 | 'bindtouchcancel',
12 | 'bindlongtap',
13 | 'animation'
14 | ]
15 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/editor.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'read-only',
3 | 'placeholder',
4 | 'show-img-size',
5 | 'show-img-toolbar',
6 | 'show-img-resize',
7 | 'bindready',
8 | 'bindfocus',
9 | 'bindblur',
10 | 'bindinput',
11 | 'bindstatuschange',
12 | 'animation'
13 | ]
14 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/picker-view.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'value',
6 | 'indicator-style',
7 | 'indicator-class',
8 | 'mask-style',
9 | 'mask-class',
10 | 'bindchange',
11 | 'bindpickstart',
12 | 'bindpickend',
13 | 'animation'
14 | ]
15 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/audio.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'src',
6 | 'loop',
7 | 'controls',
8 | 'poster',
9 | 'name',
10 | 'author',
11 | 'binderror',
12 | 'bindplay',
13 | 'bindpause',
14 | 'bindtimeupdate',
15 | 'bindended',
16 | 'animation'
17 | ]
18 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/picker.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'range',
6 | 'range-key',
7 | 'value',
8 | 'bindchange',
9 | 'bindcancel',
10 | 'bindcolumnchange',
11 | 'start',
12 | 'end',
13 | 'fields',
14 | 'custom-item',
15 | 'disabled',
16 | 'animation'
17 | ]
18 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/canvas.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'style',
4 | 'class',
5 | 'width',
6 | 'height',
7 | 'disable-scroll',
8 | 'type',
9 | 'canvas-id',
10 | 'bindtouchstart',
11 | 'bindtouchmove',
12 | 'bindtouchend',
13 | 'bindtouchcancel',
14 | 'bindlongtap',
15 | 'binderror',
16 | 'animation'
17 | ]
18 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/progress.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'percent',
6 | 'show-info',
7 | 'border-radius',
8 | 'font-size',
9 | 'stroke-width',
10 | 'color',
11 | 'activeColor',
12 | 'backgroundColor',
13 | 'active',
14 | 'active-mode',
15 | 'bindactiveend',
16 | 'animation'
17 | ]
18 |
--------------------------------------------------------------------------------
/packages/core/src/constants.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | PLUGIN_NAME: 'MinaWebpackPlugin',
3 |
4 | APP_CONFIG_FILE_NAME: 'app.config.js',
5 | COMPONENT_CONFIG_FILE_NAME: 'index.config.js',
6 |
7 | WORKER_DIRECTORY: '~worker',
8 | WORKER_ENTRY: '~worker/index.js',
9 | WORKER_CHUNK_NAME: '~worker/index',
10 |
11 | APP_CHUNK_NAME: 'app',
12 |
13 | LOADER_EXPORT_PREFIX: "'use mina'"
14 | }
15 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/navigator.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'open-type',
6 | 'hover-class',
7 | 'hover-start-time',
8 | 'hover-stay-time',
9 | 'url',
10 | 'target',
11 | 'delta',
12 | 'app-id',
13 | 'path',
14 | 'extra-data',
15 | 'version',
16 | 'hover-stop-propagation',
17 | 'bindsuccess',
18 | 'bindfail',
19 | 'bindcomplete',
20 | 'animation'
21 | ]
22 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/slider.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'name',
6 | 'min',
7 | 'color',
8 | 'max',
9 | 'step',
10 | 'disabled',
11 | 'value',
12 | 'show-value',
13 | 'activeColor',
14 | 'backgroundColor',
15 | 'track-size',
16 | 'block-size',
17 | 'block-color',
18 | 'bindvhange',
19 | 'bindchanging',
20 | 'selected-color',
21 | 'animation'
22 | ]
23 |
--------------------------------------------------------------------------------
/packages/mina-assets-loader/src/utils.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import rfs from 'require-from-string'
3 | import { transformSync } from '@babel/core'
4 |
5 | function requireFromString (code) {
6 | const transformation = transformSync(code, {
7 | configFile: path.join(__dirname, '..', '.babelrc'),
8 | ast: false
9 | })
10 | return rfs(transformation.code).default
11 | }
12 |
13 | module.exports = {
14 | requireFromString,
15 | rfs
16 | }
17 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Miao.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { View, Text } from 'remax/wechat'
3 |
4 | import MiaoJpg from './Index/gua.jpg'
5 |
6 | function MiaoPage () {
7 | const [state, setState] = useState()
8 | useEffect(() => {
9 | setState('🐱')
10 | console.log(MiaoJpg)
11 | }, [])
12 | // return state
13 | return
14 | {state}
15 |
16 | }
17 |
18 | export default MiaoPage
19 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/movable-view.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'class',
3 | 'style',
4 | 'id',
5 | 'direction',
6 | 'inertia',
7 | 'out-of-bounds',
8 | 'x',
9 | 'y',
10 | 'damping',
11 | 'friction',
12 | 'disabled',
13 | 'scale',
14 | 'scale-min',
15 | 'scale-max',
16 | 'scale-value',
17 | 'animation',
18 | 'bindchange',
19 | 'bindscale',
20 | 'htouchmove',
21 | 'vtouchmove',
22 | 'animation'
23 | ]
24 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/live-player.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'src',
6 | 'mode',
7 | 'autoplay',
8 | 'muted',
9 | 'orientation',
10 | 'object-fit',
11 | 'background',
12 | 'min-cache',
13 | 'max-cache',
14 | 'sound-mode',
15 | 'auto-pause-if-navigate',
16 | 'auto-pause-if-open-native',
17 | 'bindstatechange',
18 | 'bindfullscreenchange',
19 | 'bindnetstatus',
20 | 'animation'
21 | ]
22 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/scroll-view.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'scroll-x',
6 | 'scroll-y',
7 | 'upper-threshold',
8 | 'lower-threshold',
9 | 'scroll-top',
10 | 'scroll-left',
11 | 'scroll-into-view',
12 | 'scroll-with-animation',
13 | 'enable-back-to-top',
14 | 'enable-flex',
15 | 'bindscrolltoupper',
16 | 'bindscrolltolower',
17 | 'bindscroll',
18 | 'bindtap',
19 | 'animation'
20 | ]
21 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/view.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'disable-scroll',
4 | 'hover-class',
5 | 'hover-start-time',
6 | 'hover-stay-time',
7 | 'hidden',
8 | 'class',
9 | 'style',
10 | 'animation',
11 | 'hover-stop-propagation',
12 | 'bindtap',
13 | 'bindtouchstart',
14 | 'bindtouchmove',
15 | 'bindtouchend',
16 | 'bindtouchcancel',
17 | 'bindlongtap',
18 | 'bindtransitionend',
19 | 'bindanimationiteration',
20 | 'bindanimationstart',
21 | 'bindanimationend',
22 | 'animation'
23 | ]
24 |
--------------------------------------------------------------------------------
/example/remax/src/pages/Index/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from 'react'
2 | import { View, Image, Text } from 'remax/wechat'
3 |
4 | import style from './index.module.sass'
5 | import MiaoJpg from './gua.jpg'
6 |
7 | function IndexPage () {
8 | const [state, setState] = useState()
9 | useEffect(() => {
10 | setState('test')
11 | console.log(process.env)
12 | }, [])
13 | // return state
14 | return
15 | {state}
16 |
17 |
18 | }
19 |
20 | export default IndexPage
21 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/swiper.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'indicator-dots',
6 | 'indicator-color',
7 | 'indicator-active-color',
8 | 'autoplay',
9 | 'current',
10 | 'interval',
11 | 'duration',
12 | 'circular',
13 | 'vertical',
14 | 'previous-margin',
15 | 'next-margin',
16 | 'display-multiple-items',
17 | 'skip-hidden-item-layout',
18 | 'easing-function',
19 | 'bindchange',
20 | 'bindtransition',
21 | 'bindanimationfinish',
22 | 'bindtap',
23 | 'animation'
24 | ]
25 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/input.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'auto-focus',
3 | 'class',
4 | 'focus',
5 | 'name',
6 | 'maxlength',
7 | 'value',
8 | 'style',
9 | 'password',
10 | 'type',
11 | 'confirm-type',
12 | 'confirm-hold',
13 | 'cursor',
14 | 'selection-start',
15 | 'selection-end',
16 | 'adjust-position',
17 | 'placeholder',
18 | 'placeholder-style',
19 | 'placeholder-class',
20 | 'disabled',
21 | 'cursor-spacing',
22 | 'bindinput',
23 | 'bindtap',
24 | 'bindfocus',
25 | 'bindblur',
26 | 'bindconfirm',
27 | 'bindkeyboardheightchange',
28 | 'animation'
29 | ]
30 |
--------------------------------------------------------------------------------
/packages/core/src/ensureRequire.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import path from 'path'
3 |
4 | function ensureRequire () {
5 | const outputPath = this.compiler.options.output.path
6 | for (const n of this.entryMap.packageNames) {
7 | ['common', 'vendor'].forEach(i => {
8 | const filename = path.resolve(outputPath, n, `./include.${i}.js`)
9 | const exists = fs.existsSync(filename)
10 |
11 | if (!exists) {
12 | fs.writeFileSync(filename, '')
13 | }
14 | })
15 | }
16 | this.entryMap = undefined
17 | }
18 |
19 | export default function (plugin, ...args) {
20 | return plugin::ensureRequire(...args)
21 | }
22 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/live-pusher.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'url',
6 | 'mode',
7 | 'autopush',
8 | 'muted',
9 | 'enable-camera',
10 | 'auto-focus',
11 | 'orientation',
12 | 'beauty',
13 | 'whiteness',
14 | 'aspect',
15 | 'min-bitrate',
16 | 'max-bitrate',
17 | 'waiting-image',
18 | 'waiting-image-hash',
19 | 'zoom',
20 | 'device-position',
21 | 'background-mute',
22 | 'mirror',
23 | 'bindstatechange',
24 | 'bindnetstatus',
25 | 'binderror',
26 | 'bindbgmstart',
27 | 'bindbgmprogress',
28 | 'bindbgmcomplete',
29 | 'animation'
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/core/src/utils.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import rfs from 'require-from-string'
3 | import { transformFileSync } from '@babel/core'
4 |
5 | function resolve (...dir) {
6 | return path.join(process.cwd(), '.', ...dir)
7 | }
8 |
9 | function resolveInside (...dir) {
10 | return path.join(__dirname, '.', ...dir)
11 | }
12 |
13 | function requireFromString (filename) {
14 | const transformation = transformFileSync(filename, {
15 | configFile: path.join(__dirname, '..', '.babelrc.js'),
16 | ast: false
17 | })
18 | return rfs(transformation.code).default
19 | }
20 |
21 | module.exports = {
22 | resolve,
23 | resolveInside,
24 | requireFromString
25 | }
26 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/button.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'class',
3 | 'id',
4 | 'style',
5 | 'type',
6 | 'plain',
7 | 'disabled',
8 | 'loading',
9 | 'form-type',
10 | 'open-type',
11 | 'hover-class',
12 | 'hover-stop-propagation',
13 | 'hover-start-time',
14 | 'hover-stay-time',
15 | 'lang',
16 | 'session-from',
17 | 'send-message-title',
18 | 'send-message-path',
19 | 'send-message-img',
20 | 'app-parameter',
21 | 'show-message-card',
22 | 'bindgetuserinfo',
23 | 'bindcontact',
24 | 'bindgetphonenumber',
25 | 'binderror',
26 | 'bindopensetting',
27 | 'bindlaunchapp',
28 | 'bindtap',
29 | 'animation'
30 | ]
31 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/textarea.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'name',
6 | 'value',
7 | 'placeholder',
8 | 'placeholder-style',
9 | 'placeholder-class',
10 | 'disabled',
11 | 'maxlength',
12 | 'auto-focus',
13 | 'focus',
14 | 'fixed',
15 | 'auto-height',
16 | 'show-count',
17 | 'controlled',
18 | 'cursor-spacing',
19 | 'cursor',
20 | 'show-confirm-bar',
21 | 'selection-start',
22 | 'selection-end',
23 | 'adjust-position',
24 | 'bindfocus',
25 | 'bindblur',
26 | 'bindlinechange',
27 | 'bindinput',
28 | 'bindconfirm',
29 | 'bindkeyboardheightchange',
30 | 'animation'
31 | ]
32 |
--------------------------------------------------------------------------------
/.babelrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "presets": [
3 | ["@babel/preset-env"]
4 | ],
5 | "plugins": [
6 | ["@babel/plugin-transform-modules-commonjs"],
7 | ["@babel/plugin-transform-for-of"],
8 | ["@babel/plugin-transform-runtime", {
9 | "helpers": false,
10 | "regenerator": true
11 | }],
12 | ["@babel/plugin-transform-destructuring"],
13 | ["@babel/plugin-proposal-object-rest-spread"],
14 | ["@babel/plugin-proposal-class-properties", {
15 | "loose": true
16 | }],
17 | ["@babel/plugin-transform-block-scoping"],
18 | ["@babel/plugin-proposal-function-bind"],
19 | ["@babel/plugin-proposal-optional-chaining"],
20 | ["@babel/plugin-syntax-jsx"]
21 | ],
22 | "sourceMaps": "inline"
23 | }
24 |
--------------------------------------------------------------------------------
/example/simple/.babelrc.js:
--------------------------------------------------------------------------------
1 | const plugins = [
2 | ["@babel/plugin-transform-for-of"],
3 | ["@babel/plugin-transform-runtime", {
4 | "helpers": false,
5 | "regenerator": true
6 | }],
7 | ["@babel/plugin-transform-regenerator"],
8 | ["@babel/plugin-transform-destructuring"],
9 | ["@babel/plugin-proposal-object-rest-spread"],
10 | ["@babel/plugin-proposal-class-properties", {
11 | loose: true
12 | }],
13 | ["@babel/plugin-transform-block-scoping"],
14 | ["@babel/plugin-proposal-function-bind"],
15 | ["@babel/plugin-proposal-optional-chaining"]
16 | ]
17 | if (process.env.NO_CONSOLE === 'true') {
18 | plugins.push([
19 | "transform-remove-console", {
20 | "exclude": ["error"]
21 | }])
22 | }
23 |
24 | module.exports = {
25 | "plugins": plugins,
26 | "sourceMaps": 'inline'
27 | }
28 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/map.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'style',
4 | 'class',
5 | 'latitude',
6 | 'longitude',
7 | 'scale',
8 | 'markers',
9 | 'polyline',
10 | 'circles',
11 | 'controls',
12 | 'polygon',
13 | 'show-location',
14 | 'include-points',
15 | 'include-padding',
16 | 'ground-overlays',
17 | 'tile-overlay',
18 | 'setting',
19 | 'covers',
20 | 'subkey',
21 | 'layer-style',
22 | 'rotate',
23 | 'skew',
24 | 'enable-3D',
25 | 'show-compass',
26 | 'show-scale',
27 | 'enable-overlooking',
28 | 'enable-zoom',
29 | 'enable-scroll',
30 | 'enable-rotate',
31 | 'enable-satellite',
32 | 'enable-traffic',
33 | 'bindtap',
34 | 'bindmarkertap',
35 | 'bindcontroltap',
36 | 'bindcallouttap',
37 | 'bindupdated',
38 | 'bindregionchange',
39 | 'bindpoitap',
40 | 'animation'
41 | ]
42 |
--------------------------------------------------------------------------------
/packages/mina-assets-loader/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mina-assets-loader",
3 | "version": "1.1.0-fix.0",
4 | "description": "",
5 | "author": "Krhougs ",
6 | "homepage": "https://github.com/oranzhang/mina-webpack-plugin#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "directories": {
10 | "lib": "lib"
11 | },
12 | "files": [
13 | "/lib"
14 | ],
15 | "publishConfig": {
16 | "registry": "https://registry.yarnpkg.com"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/oranzhang/mina-webpack-plugin.git"
21 | },
22 | "scripts": {
23 | "watch": "babel src --out-dir lib --babelrc ../../.babelrc.js -w",
24 | "build": "babel src --out-dir lib --babelrc ../../.babelrc.js"
25 | },
26 | "bugs": {
27 | "url": "https://github.com/oranzhang/mina-webpack-plugin/issues"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/packages/core/templates/component.ejs:
--------------------------------------------------------------------------------
1 | <% camelCased = function(str) { return str.replace(/-([a-z0-9])/g, function (g) { return g[1].toUpperCase(); })}%>
2 |
3 |
4 | <<%=id%> <% for(let key of props) { %> <%=key%>="{{_h.v(i.props.<%=camelCased(key)%>)}}" <% } %>>
5 | <% if (id === 'swiper') { %>
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | <% } else { %>
14 |
15 |
16 |
17 | <% } %>
18 | <%=id%>>
19 |
20 |
--------------------------------------------------------------------------------
/packages/core/src/applyStaticAssetDecoration.js:
--------------------------------------------------------------------------------
1 | import { PLUGIN_NAME } from './constants'
2 |
3 | // Webpack would merge request by default, for which `mina-asset-loader` would only run ran once.
4 | // The default behavior results in that the path of imported assets be wrong in different context.
5 | // This hook is a hack for this.
6 |
7 | const assetLoaderName = 'mina-assets-loader'
8 |
9 | async function hookAfterResolve (data) {
10 | const assetLoaderPos = data.loaders
11 | .findIndex(i => i.loader.indexOf(assetLoaderName) > -1)
12 | const assetLoaderOptions = data.loaders[assetLoaderPos]?.options
13 | if (assetLoaderPos > -1 &&
14 | !assetLoaderOptions?.template &&
15 | !assetLoaderOptions?.stylesheets) {
16 | data.request += `?${Math.random() * 1000000}`
17 | }
18 | }
19 |
20 | export default function (normalModuleFactory) {
21 | normalModuleFactory.hooks.afterResolve.tapPromise(PLUGIN_NAME, this::hookAfterResolve)
22 | }
23 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/hostComponents/video.js:
--------------------------------------------------------------------------------
1 | export const props = [
2 | 'id',
3 | 'class',
4 | 'style',
5 | 'src',
6 | 'duration',
7 | 'controls',
8 | 'danmu-list',
9 | 'danmu-btn',
10 | 'enable-danmu',
11 | 'autoplay',
12 | 'loop',
13 | 'muted',
14 | 'initial-time',
15 | 'page-gesture',
16 | 'direction',
17 | 'show-progress',
18 | 'show-fullscreen-btn',
19 | 'show-play-btn',
20 | 'show-center-play-btn',
21 | 'enable-progress-gesture',
22 | 'object-fit',
23 | 'poster',
24 | 'show-mute-btn',
25 | 'title',
26 | 'play-btn-position',
27 | 'enable-play-gesture',
28 | 'auto-pause-if-navigate',
29 | 'auto-pause-if-open-native',
30 | 'vslide-gesture',
31 | 'vslide-gesture-in-fullscreen',
32 | 'bindplay',
33 | 'bindpause',
34 | 'bindended',
35 | 'bindtimeupdate',
36 | 'bindfullscreenchange',
37 | 'bindwaiting',
38 | 'binderror',
39 | 'bindprogress',
40 | 'animation'
41 | ]
42 |
--------------------------------------------------------------------------------
/example/remax/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: 'babel-eslint',
4 | parserOptions: {
5 | sourceType: 'module'
6 | },
7 | env: {
8 | browser: true,
9 | },
10 | extends: [
11 | 'standard',
12 | 'plugin:react/recommended'
13 | ],
14 | // check if imports actually resolve
15 | settings: {
16 | react: {
17 | version: "16.9"
18 | }
19 | },
20 | plugins: [
21 | 'react'
22 | ],
23 | // add your custom rules here
24 | 'rules': {
25 | "arrow-parens": 0,
26 | "generator-star-spacing": 0,
27 | "space-before-function-paren": 0,
28 | 'react/prop-types': 0
29 | },
30 | "globals": {
31 | "wxp": true,
32 | "wx": true,
33 | "getApp": true,
34 | "getCurrentPages": true,
35 | "App": true,
36 | "Page": true,
37 | "Component": true,
38 | "worker": true,
39 | "WX_WORKER_ENTRY_PATH": true,
40 | "e": true,
41 | "t": true
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 |
2 | // https://eslint.org/docs/user-guide/configuring
3 |
4 | module.exports = {
5 | root: true,
6 | parser: 'babel-eslint',
7 | parserOptions: {
8 | sourceType: 'module'
9 | },
10 | env: {
11 | browser: true,
12 | },
13 | extends: 'standard',
14 | // check if imports actually resolve
15 | 'settings': {
16 | },
17 | plugins: [
18 | ],
19 | // add your custom rules here
20 | 'rules': {
21 | "arrow-parens": 0,
22 | "generator-star-spacing": 0,
23 | "space-before-function-paren": 0,
24 | // "prefer-bind-operator/prefer-bind-operator": 2,
25 | // allow debugger during development
26 | 'no-debugger': process.env.NODE_ENV === 'production' ? 0 : 2
27 | },
28 | "globals": {
29 | "wxp": true,
30 | "wx": true,
31 | "getApp": true,
32 | "getCurrentPages": true,
33 | "App": true,
34 | "Page": true,
35 | "Component": true,
36 | "worker": true,
37 | "WX_WORKER_ENTRY_PATH": true
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/packages/core/templates/base.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | module.exports = {
9 | v: function(value) {
10 | return value !== undefined ? value : '';
11 | }
12 | };
13 |
14 |
15 | <% for (var i = 1; i <= depth; i++) { %>
16 | <%var id = i; %>
17 | <% for (let component of components) { %>
18 | <%- include('./component.ejs', {
19 | type: component.type,
20 | props: component.props,
21 | id: component.id,
22 | templateId: id,
23 | }) %>
24 | <% } %>
25 |
26 | {{i.text}}
27 |
28 |
29 |
30 |
31 |
32 | <% } %>
33 |
--------------------------------------------------------------------------------
/example/remax/.babelrc.js:
--------------------------------------------------------------------------------
1 | const presets = [
2 | ['@babel/preset-env'], ["@babel/preset-react"],
3 | ]
4 |
5 | const plugins = [
6 | ["@babel/plugin-transform-for-of"],
7 | ["@babel/plugin-transform-regenerator"],
8 | ["@babel/plugin-transform-runtime", {
9 | "helpers": false,
10 | "regenerator": true,
11 | "absoluteRuntime": true,
12 | "loose": true
13 | }],
14 | ["@babel/plugin-transform-destructuring"],
15 | ["@babel/plugin-proposal-object-rest-spread"],
16 | ["@babel/plugin-proposal-class-properties", {
17 | loose: true
18 | }],
19 | ["@babel/plugin-transform-block-scoping"],
20 | ["@babel/plugin-proposal-function-bind"],
21 | ["@babel/plugin-proposal-optional-chaining"],
22 | ['@babel/plugin-syntax-jsx']
23 | ]
24 | if (process.env.NO_CONSOLE === 'true') {
25 | plugins.push([
26 | "transform-remove-console", {
27 | "exclude": ["error"]
28 | }])
29 | }
30 |
31 | module.exports = {
32 | "presets": presets,
33 | "plugins": plugins,
34 | "sourceMaps": 'inline'
35 | }
36 |
--------------------------------------------------------------------------------
/packages/core/src/remax/adapter/wechat/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 |
3 | export const name = 'wechat'
4 |
5 | export function hostComponents(component) {
6 | return require(`./hostComponents/${component}`)
7 | }
8 |
9 | export const extensions = {
10 | template: '.wxml',
11 | style: '.wxss',
12 | jsHelper: '.wxs'
13 | }
14 |
15 | const templateBaseDir = path.join(__dirname, '../../../../templates')
16 |
17 | export const templates = {
18 | base: path.join(templateBaseDir, 'base.ejs'),
19 | component: path.join(templateBaseDir, 'component.ejs'),
20 | page: path.join(templateBaseDir, 'page.ejs'),
21 | jsHelper: path.join(templateBaseDir, 'helper.js')
22 | }
23 |
24 | export const moduleFormat = 'cjs'
25 |
26 | // TODO: alias 方法在 remax 和 remax-cli 都重复定义了,想办法 DRY
27 | const alias = {
28 | className: 'class',
29 | activeColor: 'activeColor',
30 | backgroundColor: 'backgroundColor',
31 | onClick: 'bindtap'
32 | }
33 |
34 | export function getNativePropName(prop) {
35 | const aliasProp = alias[prop]
36 |
37 | if (aliasProp) {
38 | return aliasProp
39 | }
40 |
41 | if (prop.startsWith('on')) {
42 | return prop.toLowerCase().replace('on', 'bind')
43 | }
44 |
45 | return prop
46 | }
47 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Optional npm cache directory
40 | .npm
41 |
42 | # Optional eslint cache
43 | .eslintcache
44 |
45 | # Optional REPL history
46 | .node_repl_history
47 |
48 | # Output of 'npm pack'
49 | *.tgz
50 |
51 | # Yarn Integrity file
52 | .yarn-integrity
53 |
54 | # dotenv environment variables file
55 | .env
56 |
57 | # next.js build output
58 | .next
59 |
60 | dist
61 |
62 | node_modules
63 | lib
64 |
65 | .DS_Store
66 | .vscode/
67 |
68 | packages/*/yarn.lock
69 | packages/*/package-lock.json
--------------------------------------------------------------------------------
/packages/core/src/remax/BabelRemaxPagePlugin.js:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types'
2 | import { addNamed } from '@babel/helper-module-imports'
3 |
4 | function pageConfigExpression(path, id) {
5 | const createId = addNamed(path, 'createPageConfig', 'remax')
6 | path.insertAfter(
7 | t.exportDefaultDeclaration(
8 | t.callExpression(
9 | t.identifier('Page'), [t.callExpression(createId, [id])])))
10 | }
11 |
12 | export default () => ({
13 | visitor: {
14 | ExportDefaultDeclaration: (path) => {
15 | if (t.isExpression(path.node.declaration)) {
16 | const pageId = path.scope.generateUidIdentifier('page')
17 | const declaration = path.node.declaration
18 | path.replaceWith(t.variableDeclaration('const', [
19 | t.variableDeclarator(pageId, declaration)
20 | ]))
21 | pageConfigExpression(path, pageId)
22 | path.stop()
23 | } else if (t.isFunctionDeclaration(path.node.declaration) ||
24 | t.isClassDeclaration(path.node.declaration)) {
25 | const declaration = path.node.declaration
26 | const pageId = path.scope.generateUidIdentifierBasedOnNode(path.node)
27 | declaration.id = pageId
28 | path.replaceWith(declaration)
29 | pageConfigExpression(path, pageId)
30 | path.stop()
31 | }
32 | }
33 | }
34 | })
35 |
--------------------------------------------------------------------------------
/packages/core/src/applyChunks.js:
--------------------------------------------------------------------------------
1 | const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin')
2 |
3 | function applyAppChunk (entryMap, compilation) {
4 | const app = entryMap.app
5 |
6 | compilation.assets['app.json'] = {
7 | source: () => app.json,
8 | size: () => app.json.length
9 | }
10 |
11 | new SingleEntryPlugin(
12 | this.basePath + '/',
13 | this.remax ? `${app.js.request}?remaxApp` : app.js.request,
14 | 'app'
15 | ).apply(this.compiler)
16 | }
17 |
18 | function applyPageChunks (entryMap, compilation) {
19 | for (const packageName of entryMap.packageNames) {
20 | for (const page of entryMap[packageName].pages) {
21 | this::applyComponentChunk(page, compilation, this.compiler)
22 | }
23 | }
24 | }
25 |
26 | function applyComponentChunk (config, compilation, compiler) {
27 | new SingleEntryPlugin(
28 | this.basePath,
29 | this.remax ? `${config.js.request}?remaxPage` : config.js.request,
30 | config.distBasePath
31 | ).apply(this.compiler)
32 | compilation.assets[`${config.distBasePath}.json`] = {
33 | source: () => config.json,
34 | size: () => config.json.length
35 | }
36 | }
37 |
38 | function applyChunks (compilation) {
39 | const entryMap = this.entryMap
40 |
41 | this::applyAppChunk(entryMap, compilation)
42 | this::applyPageChunks(entryMap, compilation)
43 |
44 | return []
45 | }
46 |
47 | export default function (plugin, ...args) {
48 | return plugin::applyChunks(...args)
49 | }
50 |
--------------------------------------------------------------------------------
/packages/core/src/remax/BabelRemaxAppPlugin.js:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types'
2 | import { addNamed } from '@babel/helper-module-imports'
3 |
4 | function appConfigExpression(path, id) {
5 | const createId = addNamed(path, 'createAppConfig', 'remax')
6 | path.insertAfter(
7 | t.exportDefaultDeclaration(
8 | t.callExpression(
9 | t.identifier('App'), [t.callExpression(createId, [id])])))
10 | }
11 |
12 | export default () => ({
13 | visitor: {
14 | ExportDefaultDeclaration: (path) => {
15 | if (t.isExpression(path.node.declaration)) {
16 | const appId = path.scope.generateUidIdentifier('app')
17 | const declaration = path.node.declaration
18 | path.replaceWith(t.variableDeclaration('const', [
19 | t.variableDeclarator(appId, declaration)
20 | ]))
21 | appConfigExpression(path, appId)
22 | path.stop()
23 | } else if (t.isFunctionDeclaration(path.node.declaration) ||
24 | t.isClassDeclaration(path.node.declaration)) {
25 | const declaration = path.node.declaration
26 | const appId = path.scope.generateUidIdentifierBasedOnNode(path.node)
27 | declaration.id = appId
28 | path.replaceWith(declaration)
29 | appConfigExpression(path, appId)
30 | path.stop()
31 | }
32 | },
33 | Identifier: (path) => {
34 | // 防止跟小程序的 App 冲突
35 | if (path.node.name === 'App') {
36 | path.scope.rename('App', path.scope.generateUidIdentifier('App').name)
37 | }
38 | }
39 | }
40 | })
41 |
--------------------------------------------------------------------------------
/packages/core/src/applySplitting.js:
--------------------------------------------------------------------------------
1 | import SplitChunksPlugin from 'webpack/lib/optimize/SplitChunksPlugin'
2 |
3 | function applySplitting (entryMap) {
4 | const nodeModuleRegex = /[\\/]node_modules[\\/]/
5 | const groupBase = {
6 | minChunks: 1,
7 | reuseExistingChunk: true,
8 | enforce: true
9 | }
10 | const cacheGroups = {}
11 | for (const packageName of entryMap.packageNames) {
12 | const chunkRegex = new RegExp(`^${packageName}\\/(.+)$`, 'g')
13 | const testChunk = function (chunk) {
14 | if (packageName === 'main' && chunk.name === 'app') { return true }
15 | return chunk.name && chunk.name.match(chunkRegex)
16 | }
17 |
18 | cacheGroups[`${packageName}Vendor`] = {
19 | test: nodeModuleRegex,
20 | chunks: testChunk,
21 | name: `${packageName}/include.vendor`,
22 | ...groupBase
23 | }
24 | cacheGroups[`${packageName}Common`] = {
25 | test (module) {
26 | if (module.request?.indexOf && module.request.indexOf('mina-assets-loader') > -1) {
27 | return false
28 | }
29 | return module.resource &&
30 | !module.resource.match(nodeModuleRegex)
31 | },
32 | chunks: testChunk,
33 | name: `${packageName}/include.common`,
34 | ...groupBase
35 | }
36 | }
37 | new SplitChunksPlugin({
38 | chunks: 'all',
39 | minSize: 0,
40 | maxInitialRequests: 1024,
41 | name: false,
42 | automaticNameDelimiter: '~',
43 | cacheGroups
44 | }).apply(this.compiler)
45 | }
46 |
47 | export default function (plugin, ...args) {
48 | return plugin::applySplitting(...args)
49 | }
50 |
--------------------------------------------------------------------------------
/packages/core/src/applyChunkAssets.js:
--------------------------------------------------------------------------------
1 | import { ConcatSource } from 'webpack-sources'
2 | import rfs from 'require-from-string'
3 |
4 | import { PLUGIN_NAME, LOADER_EXPORT_PREFIX } from './constants'
5 |
6 | import applyRemaxAssets from './remax/applyRemaxAssets'
7 |
8 | async function applyNormalAssets (chunks, compilation) {
9 | for (const c of chunks) {
10 | for (const m of c.getModules()) {
11 | if (m._source) {
12 | const content = m._source._value
13 | if (content.startsWith(LOADER_EXPORT_PREFIX)) {
14 | const config = rfs(content)
15 |
16 | if (config.options?.template) {
17 | const key = c.name + '.wxml'
18 | compilation.assets[key] = compilation.assets[key]
19 | ? new ConcatSource(compilation.assets[key], '\n', config.content)
20 | : new ConcatSource(config.content)
21 | } else if (config.options?.stylesheets || config.__MINA?.options.stylesheets) {
22 | const key = 'app.wxss'
23 | if (config.__MINA?.options.cssModules) {
24 | compilation.assets[key] = compilation.assets[key]
25 | ? new ConcatSource(compilation.assets[key], '\n', config.__MINA.stylesheets)
26 | : new ConcatSource(config.__MINA.stylesheets)
27 | } else {
28 | compilation.assets[key] = compilation.assets[key]
29 | ? new ConcatSource(compilation.assets[key], '\n', config.content)
30 | : new ConcatSource(config.content)
31 | }
32 | }
33 | }
34 | }
35 | }
36 | }
37 | }
38 |
39 | function applyChunkAssets (compilation) {
40 | compilation.hooks.optimizeChunkAssets.tapPromise(PLUGIN_NAME, chunks => {
41 | const promises = [
42 | this::applyNormalAssets(chunks, compilation)
43 | ]
44 | if (this.remax) {
45 | promises.push(this::applyRemaxAssets(chunks, compilation))
46 | }
47 | return Promise.all(promises)
48 | })
49 | }
50 |
51 | export default function (plugin, ...args) {
52 | return plugin::applyChunkAssets(...args)
53 | }
54 |
--------------------------------------------------------------------------------
/packages/core/src/applyChunkDecorations.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { ConcatSource } from 'webpack-sources'
3 | import Template from 'webpack/lib/Template'
4 |
5 | import {
6 | PLUGIN_NAME,
7 | WORKER_CHUNK_NAME
8 | } from './constants'
9 |
10 | function applyChunkDecorations (compilation) {
11 | const chunkNameRegex = /^(.+)\/(pages|components).+$/
12 | const windowRegExp = new RegExp('window', 'g')
13 | compilation.chunkTemplate.hooks.render.tap(PLUGIN_NAME, (source, chunk) => {
14 | return new ConcatSource(source.source().replace(windowRegExp, 'wx'))
15 | })
16 | compilation.mainTemplate.hooks.localVars.tap(PLUGIN_NAME, (source, chunk, hash) => {
17 | return Template.asString([
18 | source,
19 | '// The module cache',
20 | 'wx.__webpack_installedModules = wx.__webpack_installedModules || {};',
21 | 'var installedModules = wx.__webpack_installedModules;'
22 | ])
23 | })
24 | compilation.mainTemplate.hooks.render.tap(PLUGIN_NAME, (source, chunk) => {
25 | let groupName
26 | let injectContent = ''
27 | if (chunk.name === WORKER_CHUNK_NAME) {
28 | groupName = WORKER_CHUNK_NAME
29 | } else {
30 | groupName = chunk.name === 'app'
31 | ? 'main' : chunk.name.match(chunkNameRegex)[1]
32 | const relativePath = path.relative(
33 | path.dirname(path.resolve(this.basePath, chunk.name)),
34 | path.resolve(this.basePath, `${groupName}/include`)
35 | )
36 | const posixPath = relativePath.replace(/\\/g, '/')
37 | injectContent = `
38 | \n;(function () {
39 | if (!(wx.webpackJsonp && wx.webpackJsonp.length)) {
40 | ${
41 | ['common', 'vendor']
42 | .map(i => `require('./${posixPath}.${i}.js')`)
43 | .join(';')
44 | }
45 | }
46 | })()\n
47 | `
48 | }
49 | return new ConcatSource(source.source().replace(windowRegExp, 'wx'), injectContent)
50 | })
51 | }
52 |
53 | export default function (plugin, ...args) {
54 | return plugin::applyChunkDecorations(...args)
55 | }
56 |
--------------------------------------------------------------------------------
/packages/core/src/remax/applyRemaxAssets.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { renderFile } from 'ejs'
3 | import { ConcatSource } from 'webpack-sources'
4 |
5 | import { getComponents } from './BabelRemaxComponentPlugin'
6 | import * as adapter from './adapter/wechat'
7 |
8 | async function applyBaseTemplate (chunks, compilation) {
9 | const components = getComponents()
10 | const code = await renderFile(adapter.templates.base, {
11 | components,
12 | depth: 20
13 | })
14 |
15 | for (const n of this.entryMap.packageNames) {
16 | compilation.assets[path.join(n, `base${adapter.extensions.template}`)] = new ConcatSource(code)
17 | }
18 | }
19 |
20 | async function applyHelperFile (chunks, compilation) {
21 | const code = await renderFile(adapter.templates.jsHelper, {
22 | target: adapter.name
23 | })
24 |
25 | for (const n of this.entryMap.packageNames) {
26 | compilation.assets[path.join(n, `helper${adapter.extensions.jsHelper}`)] = new ConcatSource(code)
27 | }
28 | }
29 |
30 | async function applyEntryTemplates (chunks, compilation) {
31 | return Promise.all(
32 | chunks.map(c => (
33 | async () => {
34 | if (!this::isRemaxChunk(c)) { return }
35 | const templateCode = await renderFile(adapter.templates.page, {
36 | baseTemplate: `../../base${adapter.extensions.template}`,
37 | jsHelper: `../../helper${adapter.extensions.jsHelper}`
38 | })
39 |
40 | compilation.assets[`${c.name}${adapter.extensions.template}`] = new ConcatSource(templateCode)
41 | }
42 | )())
43 | )
44 | }
45 |
46 | function isRemaxChunk (chunk) {
47 | if (chunk.name.indexOf('/pages/') > -1) {
48 | const module = chunk.entryModule
49 |
50 | if (!(module && module.constructor && module.constructor.name)) {
51 | return false
52 | }
53 |
54 | if (module.constructor.name === 'ConcatenatedModule') {
55 | return module.rootModule.loaders.findIndex(l => l.__remax) > -1
56 | }
57 |
58 | return module.loaders.findIndex(l => l.__remax) > -1
59 | }
60 | return false
61 | }
62 |
63 | function applyRemaxAssets (chunks, compilation) {
64 | return Promise.all([
65 | this::applyBaseTemplate(chunks, compilation),
66 | this::applyHelperFile(chunks, compilation),
67 | this::applyEntryTemplates(chunks, compilation)
68 | ])
69 | }
70 |
71 | export default applyRemaxAssets
72 |
--------------------------------------------------------------------------------
/packages/core/templates/helper.js:
--------------------------------------------------------------------------------
1 | var tree = {
2 | root: {
3 | children: [],
4 | },
5 | };
6 |
7 | function reduce(action) {
8 | switch (action.type) {
9 | case 'splice':
10 | for (var i = 0; i < action.payload.length; i += 1) {
11 | var value = get(tree, action.payload[i].path);
12 | if (action.payload[i].item) {
13 | value.splice(
14 | action.payload[i].start,
15 | action.payload[i].deleteCount,
16 | action.payload[i].item
17 | );
18 | } else {
19 | value.splice(action.payload[i].start, action.payload[i].deleteCount);
20 | }
21 | set(tree, action.payload[i].path, value);
22 | }
23 | return tree;
24 | default:
25 | return tree;
26 | }
27 | }
28 |
29 | function getKey(key) {
30 | var intKey = parseInt(key);
31 | if (intKey.toString() === key) {
32 | return intKey;
33 | }
34 | return key;
35 | }
36 |
37 | function set(obj, path, value) {
38 | if (typeof path === 'string') {
39 | path = path.split('.').map(getKey);
40 | }
41 |
42 | if (path.length === 1) {
43 | obj[currentPath] = value;
44 | }
45 |
46 | var nextObj = obj;
47 | for (var i = 0; i < path.length; i += 1) {
48 | var currentPath = path[i];
49 | var currentValue = nextObj[currentPath];
50 |
51 | if (currentValue === void 0) {
52 | //check if we assume an array
53 | if (typeof path[i + 1] === 'number') {
54 | nextObj[currentPath] = [];
55 | } else {
56 | nextObj[currentPath] = {};
57 | }
58 | }
59 |
60 | if (i === path.length - 1) {
61 | nextObj[currentPath] = value;
62 | }
63 |
64 | nextObj = nextObj[currentPath];
65 | }
66 | }
67 |
68 | function get(obj, path) {
69 | if (typeof path === 'string') {
70 | path = path.split('.').map(getKey);
71 | }
72 |
73 | var nextObj = obj;
74 | for (var i = 0; i < path.length; i += 1) {
75 | var currentPath = path[i];
76 | nextObj = nextObj[currentPath];
77 | if (nextObj === void 0) {
78 | if (currentPath === 'children') {
79 | nextObj = [];
80 | } else {
81 | nextObj = {};
82 | }
83 | }
84 | }
85 |
86 | return nextObj;
87 | }
88 |
89 | <% if (target === 'alipay') { %>
90 | export default {
91 | reduce
92 | }
93 | <% } else { %>
94 | module.exports = {
95 | reduce: reduce,
96 | };
97 | <% } %>
--------------------------------------------------------------------------------
/packages/mina-assets-loader/src/index.js:
--------------------------------------------------------------------------------
1 | import { getOptions, interpolateName } from 'loader-utils'
2 | import path from 'path'
3 |
4 | import { rfs } from './utils'
5 |
6 | const cssModuleRegex = /require\("(.+)\/node_modules\//
7 |
8 | function findEntry (mod) {
9 | if (mod.reasons.length > 0 && mod.reasons[0]?.module?.resource) {
10 | return findEntry(mod.reasons[0].module)
11 | }
12 | return mod
13 | }
14 |
15 | export default function (content, map, data) {
16 | const options = {
17 | template: false,
18 | stylesheets: false,
19 | cssModules: false,
20 | useRelativePath: true,
21 | ...getOptions(this)
22 | }
23 |
24 | if (options.stylesheets && options.cssModules) {
25 | const module = rfs(
26 | String(content).replace(cssModuleRegex, 'require("')
27 | )
28 |
29 | return `'use mina'
30 | module.exports = ${JSON.stringify({
31 | ...module.locals,
32 | __MINA: {
33 | options,
34 | stylesheets: module.toString()
35 | }
36 | })}`
37 | }
38 |
39 | if (options.stylesheets || options.template) {
40 | return `'use mina'\nmodule.exports = ${JSON.stringify({
41 | content: String(content),
42 | options
43 | })}`
44 | }
45 |
46 | let entry
47 | let page
48 |
49 | try {
50 | const entryNames = findEntry(this._module)
51 | .reasons[0].dependency.loc.name
52 | .split('/').filter(i => i)
53 | entry = entryNames[0]
54 | page = entryNames[2]
55 | } catch (error) {
56 | entry = 'main'
57 | }
58 |
59 | const entryPrefix = entry === 'main' ? 'main/' : ''
60 | const outputFilename = interpolateName(
61 | this,
62 | '[name].[hash:12].[ext]',
63 | {
64 | context: this.rootContext,
65 | content
66 | }
67 | )
68 |
69 | const outputPath = `/${entryPrefix}assets/${outputFilename}`
70 | this.emitFile(outputPath, content)
71 |
72 | if (!page || !options.useRelativePath) {
73 | return `module.exports = ${JSON.stringify(outputPath)}`
74 | }
75 |
76 | let relativePath
77 | try {
78 | const pagePath = `${entry}/pages/${page}/`
79 | relativePath = path.relative(
80 | pagePath,
81 | `${entry}/assets/${outputFilename}`
82 | )
83 | } catch (error) {
84 | relativePath = outputPath
85 | }
86 |
87 | return `module.exports = ${JSON.stringify(relativePath)}`
88 | }
89 |
90 | export const raw = true
91 |
--------------------------------------------------------------------------------
/packages/core/src/remax/BabelRemaxComponentPlugin.js:
--------------------------------------------------------------------------------
1 | import * as t from '@babel/types'
2 | import { get } from 'dot-prop'
3 | import { kebabCase } from 'lodash'
4 |
5 | let components = {}
6 |
7 | function shouldRegisterAllProps(adapter, node, componentName) {
8 | if (node.openingElement.attributes.find(a => a.type === 'JSXSpreadAttribute')) {
9 | return true
10 | }
11 | return false
12 | }
13 |
14 | export default (adapter) => () => {
15 | return ({
16 | visitor: {
17 | JSXElement(path) {
18 | const node = path.node
19 | if (t.isJSXIdentifier(node.openingElement.name)) {
20 | const tagName = node.openingElement.name.name
21 | const binding = path.scope.getBinding(tagName)
22 | if (!binding) {
23 | return
24 | }
25 | const componentPath = get(binding, 'path')
26 | if (!componentPath ||
27 | !t.isImportSpecifier(componentPath.node) ||
28 | !t.isImportDeclaration(componentPath.parent) ||
29 | !componentPath.parent.source.value.startsWith('remax/')) {
30 | return
31 | }
32 | const componentName = componentPath.node.imported.name
33 | const id = kebabCase(componentName)
34 | if (id === 'swiper-item') {
35 | return
36 | }
37 |
38 | let usedProps = adapter.hostComponents(id).props
39 | if (!shouldRegisterAllProps(adapter, node, componentName)) {
40 | usedProps = node.openingElement.attributes.map(e => {
41 | const propName = get(e, 'name.name')
42 | return propName
43 | })
44 | }
45 | const props = usedProps
46 | .filter(prop => !!prop)
47 | .map(prop => adapter.getNativePropName(prop))
48 | if (!components[id]) {
49 | components[id] = {
50 | type: kebabCase(componentName),
51 | id,
52 | props
53 | }
54 | }
55 | props.forEach(prop => {
56 | if (components[id].props.findIndex(item => item === prop) !== -1) {
57 | return
58 | }
59 | components[id].props.push(prop)
60 | })
61 | }
62 | }
63 | }
64 | })
65 | }
66 |
67 | export function resetComponents () {
68 | components = {}
69 | }
70 |
71 | export function getComponents() {
72 | return Object.values(components)
73 | }
74 |
--------------------------------------------------------------------------------
/packages/core/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mina-webpack-plugin",
3 | "version": "3.0.7",
4 | "description": "",
5 | "author": "Krhougs Taengs ",
6 | "homepage": "https://github.com/oranzhang/mina-webpack-plugin#readme",
7 | "license": "MIT",
8 | "main": "lib/index.js",
9 | "directories": {
10 | "lib": "lib",
11 | "node_modules": "node_modules",
12 | "templates": "templates"
13 | },
14 | "files": [
15 | "lib",
16 | "node_modules",
17 | "templates",
18 | ".babelrc.js"
19 | ],
20 | "publishConfig": {
21 | "registry": "https://registry.yarnpkg.com"
22 | },
23 | "repository": {
24 | "type": "git",
25 | "url": "git+https://github.com/oranzhang/mina-webpack-plugin.git"
26 | },
27 | "scripts": {
28 | "watch": "babel src --out-dir lib --babelrc ../../.babelrc.js -w",
29 | "build": "babel src --out-dir lib --babelrc ../../.babelrc.js"
30 | },
31 | "bugs": {
32 | "url": "https://github.com/oranzhang/mina-webpack-plugin/issues"
33 | },
34 | "dependencies": {
35 | "@babel/cli": "^7.5.5",
36 | "@babel/core": "^7.5.5",
37 | "@babel/plugin-proposal-class-properties": "^7.5.5",
38 | "@babel/plugin-proposal-decorators": "^7.4.4",
39 | "@babel/plugin-proposal-function-bind": "^7.2.0",
40 | "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
41 | "@babel/plugin-proposal-optional-chaining": "^7.2.0",
42 | "@babel/plugin-syntax-function-bind": "^7.2.0",
43 | "@babel/plugin-syntax-jsx": "^7.2.0",
44 | "@babel/plugin-transform-async-to-generator": "^7.5.0",
45 | "@babel/plugin-transform-block-scoping": "^7.5.5",
46 | "@babel/plugin-transform-computed-properties": "^7.0.0",
47 | "@babel/plugin-transform-for-of": "^7.4.4",
48 | "@babel/plugin-transform-function-name": "^7.4.4",
49 | "@babel/plugin-transform-literals": "^7.0.0",
50 | "@babel/plugin-transform-modules-commonjs": "^7.5.0",
51 | "@babel/plugin-transform-parameters": "^7.4.4",
52 | "@babel/plugin-transform-regenerator": "^7.4.5",
53 | "@babel/plugin-transform-runtime": "^7.5.5",
54 | "@babel/plugin-transform-template-literals": "^7.4.4",
55 | "@babel/plugin-transform-unicode-regex": "^7.4.4",
56 | "@babel/polyfill": "^7.4.4",
57 | "@babel/preset-env": "^7.5.5",
58 | "@babel/runtime": "^7.5.5",
59 | "acorn-jsx": "^5.0.2",
60 | "acron": "^1.0.5",
61 | "dot-prop": "^5.1.0",
62 | "dotenv": "^8.1.0",
63 | "dotenv-expand": "^5.1.0",
64 | "ejs": "^2.7.1",
65 | "require-from-string": "^2.0.2"
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/packages/core/src/remax/applyEntryDecoration.js:
--------------------------------------------------------------------------------
1 | import fs from 'fs'
2 | import { Parser } from 'acorn'
3 | import { PLUGIN_NAME } from '../constants'
4 |
5 | import BabelRemaxPagePlugin from './BabelRemaxPagePlugin'
6 | import BabelRemaxAppPlugin from './BabelRemaxAppPlugin'
7 |
8 | const JSXParser = Parser.extend(
9 | require('acorn-jsx')()
10 | )
11 |
12 | function isRemaxPageRequest (data) {
13 | if (data.resource) {
14 | const code = String(fs.readFileSync(data.resource))
15 | const ast = JSXParser.parse(code, {
16 | ecmaVersion: 6,
17 | sourceType: 'module'
18 | })
19 | return ast.body.every(node => !(
20 | node.type === 'ExpressionStatement' &&
21 | node.expression.type === 'CallExpression' &&
22 | node.expression.callee.type === 'Identifier' &&
23 | node.expression.callee.name === 'Page' &&
24 | node.expression.arguments.length > 0 &&
25 | node.expression.arguments[0].type === 'ObjectExpression'
26 | ))
27 | }
28 | return false
29 | }
30 |
31 | function isRemaxAppRequest (data) {
32 | if (data.resource) {
33 | const code = String(fs.readFileSync(data.resource))
34 | const ast = JSXParser.parse(code, {
35 | ecmaVersion: 6,
36 | sourceType: 'module'
37 | })
38 | return ast.body.every(node => !(
39 | node.type === 'ExpressionStatement' &&
40 | node.expression.type === 'CallExpression' &&
41 | node.expression.callee.type === 'Identifier' &&
42 | node.expression.callee.name === 'App' &&
43 | node.expression.arguments.length > 0 &&
44 | node.expression.arguments[0].type === 'ObjectExpression'
45 | ))
46 | }
47 | return false
48 | }
49 |
50 | async function hookAfterResolve (data) {
51 | if (data.rawRequest?.endsWith('?remaxApp')) {
52 | ['rawRequest', 'request', 'resource', 'userRequest'].forEach(k => {
53 | data[k] = data[k].replace(/\?remaxApp$/, '')
54 | })
55 | data.isRemaxApp = isRemaxAppRequest(data)
56 |
57 | if (data.isRemaxApp) {
58 | data.loaders.unshift({
59 | loader: require.resolve('babel-loader'),
60 | __remax: true,
61 | options: {
62 | plugins: [BabelRemaxAppPlugin]
63 | }
64 | })
65 | }
66 | }
67 |
68 | if (data.rawRequest?.endsWith('?remaxPage')) {
69 | ['rawRequest', 'request', 'resource', 'userRequest'].forEach(k => {
70 | data[k] = data[k].replace(/\?remaxPage$/, '')
71 | })
72 | data.isRemaxPage = isRemaxPageRequest(data)
73 |
74 | if (data.isRemaxPage) {
75 | data.loaders.unshift({
76 | loader: require.resolve('babel-loader'),
77 | __remax: true,
78 | options: {
79 | plugins: [BabelRemaxPagePlugin]
80 | }
81 | })
82 | }
83 | }
84 | }
85 |
86 | export default function (normalModuleFactory) {
87 | normalModuleFactory.hooks.afterResolve.tapPromise(PLUGIN_NAME, this::hookAfterResolve)
88 | }
89 |
--------------------------------------------------------------------------------
/packages/core/src/index.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { resolve } from './utils'
3 |
4 | import { PLUGIN_NAME } from './constants'
5 |
6 | import getEntryMap from './getEntryMap'
7 | import applySplitting from './applySplitting'
8 | import applyChunks from './applyChunks'
9 | import applyChunkDecorations from './applyChunkDecorations'
10 | import applyChunkAssets from './applyChunkAssets'
11 | import ensureRequire from './ensureRequire'
12 | import applyStaticAssetDecoration from './applyStaticAssetDecoration'
13 | import injectEnv from './injectEnv'
14 |
15 | import BabelRemaxComponentPlugin from './remax/BabelRemaxComponentPlugin'
16 | import * as RemaxWechatAdapter from './remax/adapter/wechat'
17 | import applyEntryDecoration from './remax/applyEntryDecoration'
18 |
19 | export default class MinaWebpackPlugin {
20 | constructor (options) {
21 | this.normalizeOptions(options)
22 | this.resolveEntries = this.resolveEntries.bind(this)
23 | this.resolveBasePath = this.resolveBasePath.bind(this)
24 | global.__minaWebpackPlugin = this
25 | }
26 |
27 | apply (compiler) {
28 | this.compiler = compiler
29 | this.initialize()
30 | }
31 |
32 | initialize () {
33 | this.compiler.hooks.normalModuleFactory.tap(PLUGIN_NAME, this::this.hookNormalModuleFactory)
34 | this.compiler.hooks.run.tapPromise(PLUGIN_NAME, this::this.hookRun)
35 | this.compiler.hooks.watchRun.tapPromise(PLUGIN_NAME, this::this.hookRun)
36 | this.compiler.hooks.compilation.tap(PLUGIN_NAME, this::this.hookCompilation)
37 | this.compiler.hooks.thisCompilation.tap(PLUGIN_NAME, this::this.hookThisCompilation)
38 | this.compiler.hooks.afterEmit.tap(PLUGIN_NAME, this::this.hookAfterEmit)
39 | }
40 |
41 | hookNormalModuleFactory (normalModuleFactory) {
42 | this::applyStaticAssetDecoration(normalModuleFactory)
43 | if (this.remax) {
44 | return this::applyEntryDecoration(normalModuleFactory)
45 | }
46 | }
47 |
48 | async hookRun () {
49 | this.entryMap = getEntryMap(this)
50 | this.staticAssets = []
51 | applySplitting(this, this.entryMap)
52 | return this.entryMap
53 | }
54 |
55 | hookCompilation (compilation) {
56 | applyChunkDecorations(this, compilation)
57 | }
58 |
59 | hookThisCompilation (compilation, compilationParams) {
60 | applyChunks(this, compilation)
61 | applyChunkAssets(this, compilation)
62 | injectEnv(this, compilation)
63 | }
64 |
65 | hookAfterEmit (compilation) {
66 | ensureRequire(this)
67 | }
68 |
69 | resolveEntries () {
70 | return this.entryResolver(this)
71 | }
72 |
73 | BabelRemaxComponentPlugin = BabelRemaxComponentPlugin(RemaxWechatAdapter)
74 |
75 | normalizeOptions (options = {}) {
76 | const defaultOptions = {
77 | basePath: resolve('src'),
78 | appConfig: 'app.config.js',
79 | remax: false
80 | }
81 |
82 | const ret = Object.assign({}, defaultOptions, options)
83 |
84 | Object.keys(ret).forEach(i => {
85 | this[i] = ret[i]
86 | })
87 |
88 | return ret
89 | }
90 |
91 | resolveBasePath (...args) {
92 | return path.join(this.basePath, ...args)
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mina-webpack-plugin",
3 | "version": "3.0.0",
4 | "description": "Webpack plugin for processing MINA apps (WeChat MiniPrograms).",
5 | "main": "lib/index.js",
6 | "repository": "https://github.com/oranzhang/mina-webpack-plugin",
7 | "author": "Krhougs Taengs ",
8 | "license": "MIT",
9 | "dependencies": {
10 | "dotenv": "^8.1.0",
11 | "dotenv-expand": "^5.1.0",
12 | "ejs": "^2.7.1",
13 | "fs-extra": "^8.1.0",
14 | "loader-utils": "^1.2.3",
15 | "path": "^0.12.7",
16 | "require-from-string": "^2.0.2",
17 | "webpack": "^4.39.3",
18 | "webpack-sources": "^1.4.3"
19 | },
20 | "devDependencies": {
21 | "@babel/cli": "^7.5.5",
22 | "@babel/core": "^7.5.5",
23 | "@babel/plugin-proposal-class-properties": "^7.5.5",
24 | "@babel/plugin-proposal-decorators": "^7.4.4",
25 | "@babel/plugin-proposal-function-bind": "^7.2.0",
26 | "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
27 | "@babel/plugin-proposal-optional-chaining": "^7.2.0",
28 | "@babel/plugin-syntax-function-bind": "^7.2.0",
29 | "@babel/plugin-syntax-jsx": "^7.2.0",
30 | "@babel/plugin-transform-async-to-generator": "^7.5.0",
31 | "@babel/plugin-transform-block-scoping": "^7.5.5",
32 | "@babel/plugin-transform-computed-properties": "^7.0.0",
33 | "@babel/plugin-transform-for-of": "^7.4.4",
34 | "@babel/plugin-transform-function-name": "^7.4.4",
35 | "@babel/plugin-transform-literals": "^7.0.0",
36 | "@babel/plugin-transform-modules-commonjs": "^7.5.0",
37 | "@babel/plugin-transform-parameters": "^7.4.4",
38 | "@babel/plugin-transform-regenerator": "^7.4.5",
39 | "@babel/plugin-transform-runtime": "^7.5.5",
40 | "@babel/plugin-transform-template-literals": "^7.4.4",
41 | "@babel/plugin-transform-unicode-regex": "^7.4.4",
42 | "@babel/polyfill": "^7.4.4",
43 | "@babel/preset-env": "^7.5.5",
44 | "@babel/runtime": "^7.5.5",
45 | "babel-eslint": "^10.0.3",
46 | "babel-loader": "^8.0.6",
47 | "babel-plugin-transform-async-to-module-method": "^6.24.1",
48 | "babel-plugin-transform-remove-console": "^6.9.0",
49 | "eslint": "^6.3.0",
50 | "eslint-config-standard": "^14.1.0",
51 | "eslint-loader": "^3.0.0",
52 | "eslint-plugin-import": "^2.18.2",
53 | "eslint-plugin-node": "^9.2.0",
54 | "eslint-plugin-prefer-bind-operator": "^0.0.4",
55 | "eslint-plugin-promise": "^4.2.1",
56 | "eslint-plugin-react": "^7.14.3",
57 | "eslint-plugin-standard": "^4.0.1",
58 | "lerna": "^3.16.4",
59 | "mina-webpack-plugin": "../mina-webpack-plugin/packages/core"
60 | },
61 | "scripts": {
62 | "watch": "lerna run watch --parallel",
63 | "build": "lerna run build --ignore website",
64 | "test": "lerna run --scope remax --stream test",
65 | "clean": "lerna clean",
66 | "prepack": "lerna exec -- rm -rf lib && lerna run build",
67 | "prepublishOnly": "yarn run lint && yarn run test",
68 | "postinstall": "lerna bootstrap",
69 | "lint": "eslint 'packages/*/src/**/*.{js,ts,tsx}'",
70 | "release": "lerna publish --force-publish --create-release=github",
71 | "site:build": "lerna run --scope website --stream build",
72 | "site:deploy": "lerna run --scope website --stream deploy"
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/packages/core/src/injectEnv.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs')
2 | const path = require('path')
3 | const DefinePlugin = require('webpack/lib/DefinePlugin')
4 |
5 | const appDirectory = fs.realpathSync(process.cwd())
6 | const resolveApp = relativePath => path.resolve(appDirectory, relativePath)
7 |
8 | const dotEnvPath = resolveApp('.env')
9 |
10 | const NODE_ENV = process.env.NODE_ENV || 'development'
11 |
12 | // https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
13 | const dotenvFiles = [
14 | `${dotEnvPath}.${NODE_ENV}.local`,
15 | `${dotEnvPath}.${NODE_ENV}`,
16 | // Don't include `.env.local` for `test` environment
17 | // since normally you expect tests to produce the same
18 | // results for everyone
19 | NODE_ENV !== 'test' && `${dotEnvPath}.local`,
20 | dotEnvPath
21 | ].filter(Boolean)
22 |
23 | // Load environment variables from .env* files. Suppress warnings using silent
24 | // if this file is missing. dotenv will never modify any environment variables
25 | // that have already been set. Variable expansion is supported in .env files.
26 | // https://github.com/motdotla/dotenv
27 | // https://github.com/motdotla/dotenv-expand
28 | dotenvFiles.forEach(dotenvFile => {
29 | if (fs.existsSync(dotenvFile)) {
30 | require('dotenv-expand')(
31 | require('dotenv').config({
32 | path: dotenvFile
33 | })
34 | )
35 | }
36 | })
37 |
38 | // We support resolving modules according to `NODE_PATH`.
39 | // This lets you use absolute paths in imports inside large monorepos:
40 | // https://github.com/facebook/create-react-app/issues/253.
41 | // It works similar to `NODE_PATH` in Node itself:
42 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
43 | // Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
44 | // Otherwise, we risk importing Node.js core modules into an app instead of Webpack shims.
45 | // https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
46 | // We also resolve them to make sure all tools using them work consistently.
47 | process.env.NODE_PATH = (process.env.NODE_PATH || '')
48 | .split(path.delimiter)
49 | .filter(folder => folder && !path.isAbsolute(folder))
50 | .map(folder => path.resolve(appDirectory, folder))
51 | .join(path.delimiter)
52 |
53 | // Grab NODE_ENV and MINA_APP_* environment variables and prepare them to be
54 | // injected into the application via DefinePlugin in Webpack configuration.
55 | const MINA_APP = /^MINA_APP_/i
56 |
57 | function getClientEnvironment (data) {
58 | const raw = Object.keys(process.env)
59 | .filter(key => MINA_APP.test(key))
60 | .reduce(
61 | (env, key) => {
62 | env[key] = process.env[key]
63 | return env
64 | },
65 | {
66 | // Useful for determining whether we’re running in production mode.
67 | // Most importantly, it switches React into the correct mode.
68 | NODE_ENV: process.env.NODE_ENV || 'development',
69 | ...(data || {})
70 | }
71 | )
72 | // Stringify all values so we can feed into Webpack DefinePlugin
73 | const stringified = JSON.stringify(raw)
74 |
75 | return { raw, stringified }
76 | }
77 |
78 | function injectEnv () {
79 | const routes = (() => {
80 | const ret = {}
81 | this.entryMap.packageNames
82 | .forEach(packageName => {
83 | ret[packageName] = {}
84 | this.entryMap[packageName].pages.forEach(page => {
85 | ret[packageName][page.key] = `/${page.distBasePath}`
86 | })
87 | })
88 | return ret
89 | })()
90 | new DefinePlugin({
91 | 'process.env': getClientEnvironment({
92 | APP_ROUTES: routes
93 | }).stringified
94 | }).apply(this.compiler)
95 | }
96 |
97 | export default function (plugin, ...args) {
98 | return plugin::injectEnv(...args)
99 | }
100 |
--------------------------------------------------------------------------------
/example/remax/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simple-example",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "author": "Krhougs Taengs ",
6 | "license": "MIT",
7 | "dependencies": {
8 | "react": "^16.9.0",
9 | "remax": "^1.0.15"
10 | },
11 | "devDependencies": {
12 | "@babel/core": "^7.5.5",
13 | "@babel/plugin-proposal-class-properties": "^7.5.5",
14 | "@babel/plugin-proposal-decorators": "^7.3.0",
15 | "@babel/plugin-proposal-function-bind": "^7.2.0",
16 | "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
17 | "@babel/plugin-proposal-optional-chaining": "^7.2.0",
18 | "@babel/plugin-syntax-function-bind": "^7.2.0",
19 | "@babel/plugin-transform-async-to-generator": "^7.5.0",
20 | "@babel/plugin-transform-block-scoping": "^7.5.5",
21 | "@babel/plugin-transform-computed-properties": "^7.0.0",
22 | "@babel/plugin-transform-for-of": "^7.0.0",
23 | "@babel/plugin-transform-function-name": "^7.1.0",
24 | "@babel/plugin-transform-literals": "^7.0.0",
25 | "@babel/plugin-transform-modules-commonjs": "^7.5.0",
26 | "@babel/plugin-transform-parameters": "^7.1.0",
27 | "@babel/plugin-transform-regenerator": "^7.4.5",
28 | "@babel/plugin-transform-runtime": "^7.5.5",
29 | "@babel/plugin-transform-template-literals": "^7.0.0",
30 | "@babel/plugin-transform-unicode-regex": "^7.0.0",
31 | "@babel/polyfill": "^7.0.0",
32 | "@babel/preset-env": "^7.5.5",
33 | "@babel/preset-react": "^7.0.0",
34 | "@babel/runtime": "^7.5.5",
35 | "@krhougs/postcss-rem2rpx": "^0.0.0",
36 | "@ljharb/eslint-config": "^13.1.1",
37 | "async": "^3.1.0",
38 | "babel-eslint": "10.0.2",
39 | "babel-loader": "^8.0.6",
40 | "babel-plugin-transform-async-to-module-method": "^6.24.1",
41 | "babel-plugin-transform-remove-console": "^6.9.0",
42 | "copy-webpack-plugin": "^5.0.4",
43 | "css-loader": "^3.1.0",
44 | "dotenv": "^8.0.0",
45 | "dotenv-cli": "^2.0.1",
46 | "escodegen": "^1.11.0",
47 | "eslint": "^6.1.0",
48 | "eslint-config-react-app": "^4.0.1",
49 | "eslint-config-standard": "^13.0.1",
50 | "eslint-import-resolver-webpack": "^0.11.1",
51 | "eslint-loader": "^2.2.1",
52 | "eslint-plugin-flowtype": "^3.12.2",
53 | "eslint-plugin-import": "^2.18.2",
54 | "eslint-plugin-jsx-a11y": "^6.2.3",
55 | "eslint-plugin-node": "^9.1.0",
56 | "eslint-plugin-prefer-bind-operator": "^0.0.4",
57 | "eslint-plugin-promise": "^4.2.1",
58 | "eslint-plugin-react": "^7.14.3",
59 | "eslint-plugin-react-hooks": "^1.6.1",
60 | "eslint-plugin-standard": "^4.0.0",
61 | "extract-loader": "^3.0.0",
62 | "fast-async": "^6.3.8",
63 | "file-loader": "^4.1.0",
64 | "fs-extra": "^8.1.0",
65 | "js-yaml": "^3.10.0",
66 | "js-yaml-loader": "^1.2.2",
67 | "jsdom": "^15.1.1",
68 | "json-loader": "^0.5.7",
69 | "mina-assets-loader": "^1.1.0",
70 | "mina-webpack-plugin": "^3.0.3",
71 | "nib": "^1.1.2",
72 | "node-sass": "^4.12.0",
73 | "path": "^0.12.7",
74 | "pbjs-loader": "^0.1.1",
75 | "postcss-rem2rpx": "^1.0.1",
76 | "poststylus": "^1.0.0",
77 | "pug": "^2.0.4",
78 | "pug-html-loader": "^1.1.5",
79 | "pug-loader": "^2.3.0",
80 | "raw-loader": "^3.1.0",
81 | "regenerator-runtime": "^0.13.3",
82 | "require-from-string": "^2.0.2",
83 | "requirejs": "^2.3.6",
84 | "rimraf": "^2.6.2",
85 | "sass-loader": "^7.1.0",
86 | "style-loader": "^0.23.0",
87 | "stylus": "^0.54.5",
88 | "stylus-loader": "^3.0.1",
89 | "terser-webpack-plugin": "^1.3.0",
90 | "to-string-loader": "^1.1.5",
91 | "uglifyjs-webpack-plugin": "^2.1.3",
92 | "url-loader": "^2.1.0",
93 | "vhtml": "^2.1.0",
94 | "webpack": "4.38.0",
95 | "webpack-cli": "^3.3.6",
96 | "webpack-merge": "4.2.1",
97 | "wxml-loader": "^0.3.0",
98 | "yaml-loader": "^0.5.0"
99 | },
100 | "scripts": {
101 | "clean": "rimraf dist/*",
102 | "watch": "yarn run clean; webpack --config build/webpack.config.js --watch",
103 | "watch_prod": "yarn run clean; NODE_ENV=production webpack --config build/webpack.prod.config.js --watch",
104 | "build": "yarn run clean; NODE_ENV=production webpack --config build/webpack.prod.config.js",
105 | "build_dev": "yarn run clean; webpack --config build/webpack.config.js",
106 | "debug": "yarn run clean; node --nolazy --inspect-brk=9229 node_modules/webpack-cli/bin/cli.js --config build/webpack.config.js --watch"
107 | },
108 | "peerDependencies": {}
109 | }
110 |
--------------------------------------------------------------------------------
/example/simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "simple-remax-example",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "author": "Krhougs Taengs ",
6 | "license": "MIT",
7 | "dependencies": {},
8 | "devDependencies": {
9 | "@babel/core": "^7.5.5",
10 | "@babel/plugin-proposal-class-properties": "^7.5.5",
11 | "@babel/plugin-proposal-decorators": "^7.3.0",
12 | "@babel/plugin-proposal-function-bind": "^7.2.0",
13 | "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
14 | "@babel/plugin-proposal-optional-chaining": "^7.2.0",
15 | "@babel/plugin-syntax-function-bind": "^7.2.0",
16 | "@babel/plugin-transform-async-to-generator": "^7.5.0",
17 | "@babel/plugin-transform-block-scoping": "^7.5.5",
18 | "@babel/plugin-transform-computed-properties": "^7.0.0",
19 | "@babel/plugin-transform-for-of": "^7.0.0",
20 | "@babel/plugin-transform-function-name": "^7.1.0",
21 | "@babel/plugin-transform-literals": "^7.0.0",
22 | "@babel/plugin-transform-modules-commonjs": "^7.5.0",
23 | "@babel/plugin-transform-parameters": "^7.1.0",
24 | "@babel/plugin-transform-regenerator": "^7.4.5",
25 | "@babel/plugin-transform-runtime": "^7.5.5",
26 | "@babel/plugin-transform-template-literals": "^7.0.0",
27 | "@babel/plugin-transform-unicode-regex": "^7.0.0",
28 | "@babel/polyfill": "^7.0.0",
29 | "@babel/preset-env": "^7.5.5",
30 | "@babel/preset-react": "^7.0.0",
31 | "@babel/runtime": "^7.5.5",
32 | "@krhougs/postcss-rem2rpx": "^0.0.0",
33 | "@ljharb/eslint-config": "^13.1.1",
34 | "async": "^3.1.0",
35 | "babel-eslint": "10.0.2",
36 | "babel-loader": "^8.0.6",
37 | "babel-plugin-transform-async-to-module-method": "^6.24.1",
38 | "babel-plugin-transform-remove-console": "^6.9.0",
39 | "copy-webpack-plugin": "^5.0.4",
40 | "css-loader": "^3.1.0",
41 | "dotenv": "^8.0.0",
42 | "dotenv-cli": "^2.0.1",
43 | "escodegen": "^1.11.0",
44 | "eslint": "^6.1.0",
45 | "eslint-config-react-app": "^4.0.1",
46 | "eslint-config-standard": "^13.0.1",
47 | "eslint-import-resolver-webpack": "^0.11.1",
48 | "eslint-loader": "^2.2.1",
49 | "eslint-plugin-flowtype": "^3.12.2",
50 | "eslint-plugin-import": "^2.18.2",
51 | "eslint-plugin-jsx-a11y": "^6.2.3",
52 | "eslint-plugin-node": "^9.1.0",
53 | "eslint-plugin-prefer-bind-operator": "^0.0.4",
54 | "eslint-plugin-promise": "^4.2.1",
55 | "eslint-plugin-react": "^7.14.3",
56 | "eslint-plugin-react-hooks": "^1.6.1",
57 | "eslint-plugin-standard": "^4.0.0",
58 | "extract-loader": "^3.0.0",
59 | "fast-async": "^6.3.8",
60 | "file-loader": "^4.1.0",
61 | "fs-extra": "^8.1.0",
62 | "js-yaml": "^3.10.0",
63 | "js-yaml-loader": "^1.2.2",
64 | "jsdom": "^15.1.1",
65 | "json-loader": "^0.5.7",
66 | "mina-assets-loader": "^1.0.0",
67 | "mina-webpack-plugin": "^2.0.0",
68 | "nib": "^1.1.2",
69 | "node-sass": "^4.12.0",
70 | "path": "^0.12.7",
71 | "pbjs-loader": "^0.1.1",
72 | "postcss-rem2rpx": "^1.0.1",
73 | "poststylus": "^1.0.0",
74 | "pug": "^2.0.4",
75 | "pug-html-loader": "^1.1.5",
76 | "pug-loader": "^2.3.0",
77 | "raw-loader": "^3.1.0",
78 | "regenerator-runtime": "^0.13.3",
79 | "require-from-string": "^2.0.2",
80 | "requirejs": "^2.3.6",
81 | "rimraf": "^2.6.2",
82 | "sass-loader": "^7.1.0",
83 | "style-loader": "^0.23.0",
84 | "stylus": "^0.54.5",
85 | "stylus-loader": "^3.0.1",
86 | "terser-webpack-plugin": "^1.3.0",
87 | "to-string-loader": "^1.1.5",
88 | "uglifyjs-webpack-plugin": "^2.1.3",
89 | "url-loader": "^2.1.0",
90 | "vhtml": "^2.1.0",
91 | "webpack": "4.38.0",
92 | "webpack-cli": "^3.3.6",
93 | "webpack-merge": "4.2.1",
94 | "wxml-loader": "^0.3.0",
95 | "yaml-loader": "^0.5.0"
96 | },
97 | "scripts": {
98 | "clean": "rimraf dist/*",
99 | "watch": "yarn run clean; dotenv -e .env.development webpack -- --config build/webpack.config.js --watch",
100 | "watch_prod": "yarn run clean; dotenv -e .env.production webpack -- --config build/webpack.prod.config.js --watch",
101 | "build": "yarn run clean; dotenv -e .env.production webpack -- --config build/webpack.prod.config.js",
102 | "build_dev": "yarn run clean; dotenv -e .env.development webpack -- --config build/webpack.config.js",
103 | "debug": "yarn run clean; dotenv -e .env.development node -- --nolazy --inspect-brk=9229 node_modules/webpack-cli/bin/cli.js --config build/webpack.config.js --watch"
104 | },
105 | "peerDependencies": {}
106 | }
107 |
--------------------------------------------------------------------------------
/example/simple/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | // const webpack = require('webpack')
3 |
4 | const rem2rpx = require('@krhougs/postcss-rem2rpx')
5 | const poststylus = require('poststylus')
6 |
7 | const babelConfig = require('../.babelrc')
8 |
9 | const MinaWebpackPlugin = require('../../../packages/core').default
10 | // const CopyPlugin = require('copy-webpack-plugin')
11 |
12 | function resolve (dir) {
13 | return path.join(__dirname, '..', dir)
14 | }
15 |
16 | module.exports = {
17 | mode: 'development',
18 | optimization: {},
19 | entry: () => ({}),
20 | plugins: [
21 | new MinaWebpackPlugin()
22 | // new CopyPlugin([
23 | // {
24 | // from: 'static',
25 | // to: '.',
26 | // toType: 'dir'
27 | // }
28 | // ])
29 | ].filter(function (e) { return e }),
30 | devtool: false,
31 | // performance: {
32 | // assetFilter: function(assetFilename) {
33 | // return !assetFilename.endsWith('.js')
34 | // }
35 | // },
36 | output: {
37 | path: resolve('dist'),
38 | filename: '[name].js',
39 | publicPath: '/',
40 | libraryTarget: 'commonjs2'
41 | },
42 | resolve: {
43 | modules: [
44 | 'node_modules',
45 | resolve('src'),
46 | 'lib'
47 | ],
48 | extensions: ['.js', '.jsx', '.render.jsx', '.render.js', '.json', '.pug', '.styl', '.coffee'],
49 | alias: {
50 | '@': resolve('src'),
51 | '@vendor': resolve('src/vendor'),
52 | '@misc': resolve('misc')
53 | }
54 | },
55 | module: {
56 | rules: [
57 | {
58 | test: /\.js$/,
59 | include: [/src/, /lib/],
60 | loader: 'babel-loader',
61 | options: babelConfig
62 | },
63 | {
64 | test: /\.(png|svg|jpg|gif)$/,
65 | use: [
66 | 'mina-assets-loader'
67 | ]
68 | },
69 | {
70 | test: /\.pug$/,
71 | include: /src/,
72 | use: [
73 | {
74 | loader: 'mina-assets-loader',
75 | options: {
76 | template: true
77 | }
78 | },
79 | {
80 | loader: 'wxml-loader'
81 | },
82 | {
83 | loader: 'pug-html-loader',
84 | options: {
85 | locals: {
86 | basedir: path.resolve(__dirname, '../src')
87 | },
88 | pretty: true,
89 | debug: false,
90 | cache: true,
91 | basedir: resolve('src')
92 | }
93 | }
94 | ]
95 | },
96 | {
97 | test: /\.s(a|c)ss$/,
98 | include: /src/,
99 | exclude: /\.module\.s(a|c)ss$/,
100 | use: [
101 | {
102 | loader: 'mina-assets-loader',
103 | options: {
104 | stylesheets: true
105 | }
106 | },
107 | 'extract-loader',
108 | {
109 | loader: 'css-loader',
110 | options: {
111 | url: false
112 | }
113 | },
114 | 'sass-loader'
115 | ]
116 | },
117 | {
118 | test: /\.module\.s(a|c)ss$/,
119 | include: /src/,
120 | use: [
121 | {
122 | loader: 'mina-assets-loader',
123 | options: {
124 | stylesheets: true,
125 | cssModules: true
126 | }
127 | },
128 | {
129 | loader: 'css-loader',
130 | options: {
131 | modules: {
132 | localIdentName: '[name]__[local]___[hash:base64:5]'
133 | },
134 | url: false
135 | }
136 | },
137 | 'sass-loader'
138 | ]
139 | },
140 | {
141 | test: /\.styl$/,
142 | include: /src/,
143 | use: [
144 | {
145 | loader: 'mina-assets-loader',
146 | options: {
147 | stylesheets: true
148 | }
149 | },
150 | {
151 | loader: 'extract-loader'
152 | },
153 | {
154 | loader: 'css-loader'
155 | },
156 | {
157 | loader: 'stylus-loader',
158 | options: {
159 | preferPathResolver: 'webpack',
160 | import: [
161 | '~nib/lib/nib/index.styl',
162 | '~@/utils/var.styl'
163 | ],
164 | use: [
165 | require('nib')(),
166 | poststylus([
167 | rem2rpx({
168 | scale: 2
169 | })
170 | ])
171 | ]
172 | }
173 | }
174 | ]
175 | }
176 | ]
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/example/remax/build/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path')
2 | // const webpack = require('webpack')
3 |
4 | const rem2rpx = require('@krhougs/postcss-rem2rpx')
5 | const poststylus = require('poststylus')
6 |
7 | const MinaWebpackPlugin = require('mina-webpack-plugin').default
8 | // const CopyPlugin = require('copy-webpack-plugin')
9 |
10 | const minaWebpackPlugin = new MinaWebpackPlugin({
11 | remax: true
12 | })
13 |
14 | let babelConfig = require('../.babelrc')
15 | babelConfig = {
16 | ...babelConfig,
17 | plugins: [
18 | minaWebpackPlugin.BabelRemaxComponentPlugin,
19 | ...babelConfig.plugins
20 | ]
21 | }
22 |
23 | function resolve (dir) {
24 | return path.join(__dirname, '..', dir)
25 | }
26 |
27 | module.exports = {
28 | mode: 'development',
29 | optimization: {},
30 | entry: () => ({}),
31 | plugins: [
32 | minaWebpackPlugin
33 | // new CopyPlugin([
34 | // {
35 | // from: 'static',
36 | // to: '.',
37 | // toType: 'dir'
38 | // }
39 | // ])
40 | ].filter(function (e) { return e }),
41 | devtool: false,
42 | // performance: {
43 | // assetFilter: function(assetFilename) {
44 | // return !assetFilename.endsWith('.js')
45 | // }
46 | // },
47 | output: {
48 | path: resolve('dist'),
49 | filename: '[name].js',
50 | publicPath: '/',
51 | libraryTarget: 'commonjs2'
52 | },
53 | resolve: {
54 | modules: [
55 | 'node_modules',
56 | resolve('src'),
57 | 'lib'
58 | ],
59 | extensions: ['.js', '.jsx', '.render.jsx', '.render.js', '.json', '.pug', '.styl', '.coffee'],
60 | alias: {
61 | '@': resolve('src'),
62 | '@vendor': resolve('src/vendor'),
63 | '@misc': resolve('misc')
64 | }
65 | },
66 | module: {
67 | rules: [
68 | {
69 | test: /\.js$/,
70 | include: [/src/, /lib/],
71 | loader: 'babel-loader',
72 | options: babelConfig
73 | },
74 | {
75 | test: /\.(png|svg|jpg|gif)$/,
76 | use: [
77 | 'mina-assets-loader'
78 | ]
79 | },
80 | {
81 | test: /\.pug$/,
82 | include: /src/,
83 | use: [
84 | {
85 | loader: 'mina-assets-loader',
86 | options: {
87 | template: true
88 | }
89 | },
90 | {
91 | loader: 'wxml-loader'
92 | },
93 | {
94 | loader: 'pug-html-loader',
95 | options: {
96 | locals: {
97 | basedir: path.resolve(__dirname, '../src')
98 | },
99 | pretty: true,
100 | debug: false,
101 | cache: true,
102 | basedir: resolve('src')
103 | }
104 | }
105 | ]
106 | },
107 | {
108 | test: /\.s(a|c)ss$/,
109 | include: /src/,
110 | exclude: /\.module\.s(a|c)ss$/,
111 | use: [
112 | {
113 | loader: 'mina-assets-loader',
114 | options: {
115 | stylesheets: true
116 | }
117 | },
118 | 'extract-loader',
119 | {
120 | loader: 'css-loader',
121 | options: {
122 | url: false
123 | }
124 | },
125 | 'sass-loader'
126 | ]
127 | },
128 | {
129 | test: /\.module\.s(a|c)ss$/,
130 | include: /src/,
131 | use: [
132 | {
133 | loader: 'mina-assets-loader',
134 | options: {
135 | stylesheets: true,
136 | cssModules: true
137 | }
138 | },
139 | {
140 | loader: 'css-loader',
141 | options: {
142 | modules: {
143 | localIdentName: '[name]__[local]___[hash:base64:5]'
144 | },
145 | url: false
146 | }
147 | },
148 | 'sass-loader'
149 | ]
150 | },
151 | {
152 | test: /\.styl$/,
153 | include: /src/,
154 | use: [
155 | {
156 | loader: 'mina-assets-loader',
157 | options: {
158 | stylesheets: true
159 | }
160 | },
161 | {
162 | loader: 'extract-loader'
163 | },
164 | {
165 | loader: 'css-loader'
166 | },
167 | {
168 | loader: 'stylus-loader',
169 | options: {
170 | preferPathResolver: 'webpack',
171 | import: [
172 | '~nib/lib/nib/index.styl',
173 | '~@/utils/var.styl'
174 | ],
175 | use: [
176 | require('nib')(),
177 | poststylus([
178 | rem2rpx({
179 | scale: 2
180 | })
181 | ])
182 | ]
183 | }
184 | }
185 | ]
186 | }
187 | ]
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/packages/core/src/getEntryMap.js:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import fs from 'fs'
3 |
4 | import { requireFromString } from './utils'
5 |
6 | const {
7 | WORKER_DIRECTORY,
8 | COMPONENT_CONFIG_FILE_NAME
9 | } = require('./constants')
10 |
11 | function filterComponents (components) {
12 | const ret = {}
13 | for (const key in components) {
14 | ret[key] = {
15 | usePlugin: components[key].startsWith('plugin://'),
16 | request: components[key]
17 | }
18 | }
19 | return ret
20 | }
21 |
22 | class AppConfig {
23 | constructor (options) {
24 | this.options = options
25 | this.entry = './app.js'
26 | this.pageRoutes = {}
27 | this.components = {}
28 | this.worker = null
29 | this.usingPlugin = null
30 | this.env = {}
31 | this.basePath = options.basePath
32 | this.plugin = options.plugin
33 |
34 | this.setEntry = this.setEntry.bind(this)
35 | this.setRoute = this.setRoute.bind(this)
36 | this.useComponent = this.useComponent.bind(this)
37 | this.setWorker = this.setWorker.bind(this)
38 | this.define = this.define.bind(this)
39 | }
40 |
41 | setEntry (entry) {
42 | this.entry = entry
43 | return this
44 | }
45 |
46 | setStyle (request) {
47 | this.style = request
48 | return this
49 | }
50 |
51 | setRoute (...args) {
52 | const [subPackage, route, extra] = (function () {
53 | switch (typeof args[0]) {
54 | case 'string':
55 | return [args[0], args[1], args[2] || {}]
56 | case 'object':
57 | return ['main', args[0], args[1] || {}]
58 | default:
59 | throw new TypeError('Invalid route config.')
60 | }
61 | })()
62 | this.pageRoutes[subPackage] = Object.entries(route)
63 | .map(([key, query]) => this.plugin::getComponentEntries(
64 | key,
65 | query,
66 | subPackage,
67 | true
68 | ))
69 | this.pageRoutes[subPackage].extra = extra
70 | return this
71 | }
72 |
73 | useComponent (components) {
74 | Object.assign(this.components, filterComponents(this.components))
75 | return this
76 | }
77 |
78 | setWorker (request) {
79 | this.worker = request
80 | return this
81 | }
82 |
83 | define (data) {
84 | Object.assign(this.env, data)
85 | return this
86 | }
87 |
88 | getRouteConfig () {
89 | const packages = Object.keys(this.pageRoutes).filter(i => i !== 'main')
90 | const hasSubPackages = !!packages.length
91 | return {
92 | pages: [
93 | ...this.pageRoutes.main.map(i => `main/pages/${i.key}/${i.key}`)
94 | ],
95 | ...this.pageRoutes.main.extra,
96 | subPackages: hasSubPackages
97 | ? (() => {
98 | const ret = []
99 | for (const p of packages) {
100 | ret.push({
101 | root: p,
102 | name: p,
103 | pages: this.pageRoutes[p].map(i => `pages/${i.key}/${i.key}`)
104 | // ...extra
105 | })
106 | }
107 | return ret
108 | })() : []
109 | }
110 | }
111 |
112 | getWorkerConfig () {
113 | let ret
114 | if (this.worker) {
115 | ret.worker = WORKER_DIRECTORY
116 | }
117 | return ret
118 | }
119 |
120 | getComponentConfig () {
121 | return {
122 | usingComponents: {}
123 | }
124 | }
125 |
126 | toJSON () {
127 | return JSON.stringify({
128 | ...this.rawConfig,
129 | ...this.getRouteConfig(),
130 | ...this.getWorkerConfig(),
131 | ...this.getComponentConfig()
132 | })
133 | }
134 | }
135 |
136 | class ComponentConfig {
137 | constructor (rawConfig = {}, isPage = true) {
138 | this.isPage = true
139 | this.rawConfig = rawConfig
140 | }
141 |
142 | toJSON (subPackage) {
143 | return JSON.stringify({
144 | ...this.rawConfig
145 | })
146 | }
147 | }
148 |
149 | function getComponentConfig (query) {
150 | const filenameRegex = /\.(\w+)$/
151 | const queryPath = this.resolveBasePath(query)
152 |
153 | try {
154 | const queryStats = fs.statSync(queryPath)
155 | if (queryStats.isDirectory()) {
156 | return path.join(queryPath, COMPONENT_CONFIG_FILE_NAME)
157 | }
158 | return queryPath.replace(filenameRegex, '') + '.config.js'
159 | } catch (error) {
160 | return queryPath.replace(filenameRegex, '') + '.config.js'
161 | }
162 | }
163 |
164 | function getComponentEntries (key, query, subPackage, isPage, parent) {
165 | isPage = !!isPage
166 | const distBasePath = `${subPackage}/${isPage ? 'pages' : 'components'}/${key}/${key}`
167 | const comp = new ComponentConfig(requireFromString(this::getComponentConfig(query)), isPage)
168 | return {
169 | isPage,
170 | query,
171 | key,
172 | config: comp,
173 | js: {
174 | request: query
175 | },
176 | json: comp.toJSON(subPackage),
177 | distBasePath
178 | }
179 | }
180 |
181 | function getEntryMap () {
182 | const app = new AppConfig({ plugin: this, basePath: this.basePath })
183 | app.rawConfig = requireFromString(this.resolveBasePath(this.appConfig))(app)
184 |
185 | const packageNames = Object.keys(app.pageRoutes)
186 | const packages = {}
187 | for (const p of packageNames) {
188 | packages[p] = {
189 | ...(packages[p] || {}),
190 | pages: app.pageRoutes[p]
191 | }
192 | }
193 |
194 | return {
195 | worker: app.worker
196 | ? {
197 | basePath: this.basePath,
198 | request: app.worker
199 | }
200 | : null,
201 | app: {
202 | js: {
203 | request: app.entry
204 | },
205 | json: app.toJSON()
206 | },
207 | ...packages,
208 | packageNames
209 | }
210 | }
211 |
212 | export default function (plugin) {
213 | return plugin::getEntryMap()
214 | }
215 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # MinaWebpackPlugin
2 | MINA(微信小程序) Webpack 插件。
3 |
4 | A Webpack plugin for MINA(WeChat MiniProgram).
5 |
6 | - [x] 基础打包 | basic packaging
7 | - [x] 模板打包 | packaging for templates
8 | - [x] 样式表打包与 CSS Modules | packaging for stylesheets and css modules
9 | - [x] 静态资源打包 | packaging for static resources
10 | - [ ] 自定义组件打包 | packaging for components
11 | - [ ] Source Maps
12 | - [x] remax 支持 | support for remax
13 |
14 | ## 概述 | Overview
15 | - 适用于 Webpack 4 | For Webpack 4;
16 | - 只支持微信小程序 | Compactable with WeChat MINA only;
17 | - 支持直接为使用 [Remax](https://github.com/remaxjs/remax) 的项目打包 | En duo avec [Remax](https://github.com/remaxjs/remax);
18 | - 可使用各种 pre-processors (e.g. Pug, Stylus, e.t.c.) | Compactable with variant pre-processors;
19 | - 支持 Component | Support MINA Component;
20 | - 支持分包 | Support MINA sub-package packing;
21 | - 自动合并依赖(使用 Webpack 的 `SplitChunksPlugin`) | Merge dependencies into one single file using `SplitChunksPlugin`;
22 | - 自动通过配置文件生成 `app.json` 和页面的 JSON 配置 | Genarate but not hard-coding MINA configuration JSONs;
23 | - 已在生产环境中测试并使用 | Build for/in production.
24 |
25 | ## 配置项 | Plugin Configuration
26 | ```js
27 | {
28 | // 必填,源码目录绝对对路径
29 | // required, absolute path of src directory
30 | basePath: path.join(__dirname, 'src'),
31 | // 选填,是否开启remax支持
32 | // optional, enable remax support
33 | remax: false
34 | }
35 | ```
36 |
37 | ## 开始使用 | Getting Started
38 | 在 Webpack 配置文件中初始化本插件,并将 `entry` 设置成 `() => ({})` 即可开始使用。
39 |
40 | Initialize the plugin and set `entry` to `() => ({})` to get started.
41 |
42 | ```js
43 | // webpack.config.js
44 | const MinaWebpackPlugin = require('mina-webpack-plugin').default
45 | export default {
46 | // ...
47 | entry: () => ({}),
48 | plugins: [
49 | new MinaWebpackPlugin()
50 | ]
51 | }
52 | ```
53 |
54 | [example](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/simple)
55 |
56 | [example avec Remax](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/remax)
57 |
58 | ## `mina-assets-loader`
59 | 直接使用 `mina-assets-loader` 处理静态资源。
60 |
61 | Just let `mina-assets-loader` handle the static assets.
62 |
63 | ```js
64 | // src/pages/Index/index.js
65 | import thePicture from './index.png'
66 |
67 | // webpack.config.js
68 | export default {
69 | // ...
70 | module: {
71 | rules: [
72 | {
73 | test: /\.(png|svg|jpg|gif)$/,
74 | include: /src/,
75 | use: [
76 | {
77 | loader: 'mina-assets-loader'
78 | }
79 | ]
80 | }
81 | ]
82 | }
83 | }
84 | ```
85 |
86 | ## 模板 | Templates
87 | 在页面的主 `entry` 中直接 `import` 对应的模板文件即可。在 module rules 中加入 `mina-assets-loader?template` 以让插件正确处理正确模板。
88 |
89 | Directly `import` the template file in the page `entry` to use templates. In order to let the plugin processing the template, add `mina-assets-loader?template` in module rules.
90 |
91 | ```js
92 | // src/pages/Index/index.js
93 | import './index.pug'
94 |
95 | // webpack.config.js
96 | export default {
97 | // ...
98 | module: {
99 | rules: [
100 | {
101 | test: /\.pug$/,
102 | include: /src/,
103 | use: [
104 | {
105 | loader: 'mina-assets-loader',
106 | options: {
107 | template: true
108 | }
109 | },
110 | {
111 | loader: 'wxml-loader'
112 | },
113 | {
114 | loader: 'pug-html-loader',
115 | options: {
116 | locals: {
117 | basedir: path.resolve(__dirname, '../src')
118 | },
119 | pretty: true,
120 | debug: false,
121 | cache: true,
122 | basedir: resolve('src')
123 | }
124 | }
125 | ]
126 | }
127 | ]
128 | }
129 | }
130 | ```
131 |
132 | ## 样式表与 CSS Modules | Stylesheets and CSS Modules
133 | 在页面的主 `entry` 中直接 `import` 对应的样式表文件即可。在 module rules 中加入 `mina-assets-loader?stylesheets` 以让插件正确处理正确样式表。
134 |
135 | 如需使用 CSS Modules, 开启 `css-loader` 的 `modules` 选项并同时开启 `mina-assets-loader` 的 `stylesheets` 选项与 `cssModules` 选项。
136 |
137 | Directly `import` the stylesheets file in the page `entry` to use templates. In order to let the plugin processing stylesheets, add `mina-assets-loader?stylesheets` in module rules.
138 |
139 | To use CSS Modules, enable `modules` in `css-loader` and enable both `stylesheets` and `cssModules` in `mina-assets-loader`.
140 |
141 | ```js
142 | // src/pages/Index/index.js
143 | import './index.sass'
144 | import style from './index.module.sass'
145 |
146 |
147 | // webpack.config.js
148 | export default {
149 | // ...
150 | module: {
151 | rules: [
152 | {
153 | test: /\.s(a|c)ss$/,
154 | include: /src/,
155 | exclude: /\.module\.s(a|c)ss$/,
156 | use: [
157 | {
158 | loader: 'mina-assets-loader',
159 | options: {
160 | stylesheets: true
161 | }
162 | },
163 | 'extract-loader',
164 | {
165 | loader: 'css-loader',
166 | options: {
167 | url: false
168 | }
169 | },
170 | 'sass-loader'
171 | ]
172 | },
173 | {
174 | test: /\.module\.s(a|c)ss$/,
175 | include: /src/,
176 | use: [
177 | {
178 | loader: 'mina-assets-loader',
179 | options: {
180 | stylesheets: true,
181 | cssModules: true
182 | }
183 | },
184 | {
185 | loader: 'css-loader',
186 | options: {
187 | modules: {
188 | localIdentName: '[name]__[local]___[hash:base64:5]'
189 | },
190 | url: false
191 | }
192 | },
193 | 'sass-loader'
194 | ]
195 | }
196 | ]
197 | }
198 | }
199 | ```
200 |
201 | ## 授权
202 | MIT
203 |
--------------------------------------------------------------------------------
/packages/core/README.md:
--------------------------------------------------------------------------------
1 | # MinaWebpackPlugin
2 | MINA(微信小程序) Webpack 插件。
3 |
4 | A Webpack plugin for MINA(WeChat MiniProgram).
5 |
6 | - [x] 基础打包 | basic packaging
7 | - [x] 模板打包 | packaging for templates
8 | - [x] 样式表打包与 CSS Modules | packaging for stylesheets and css modules
9 | - [x] 静态资源打包 | packaging for static resources
10 | - [ ] 自定义组件打包 | packaging for components
11 | - [ ] Source Maps
12 | - [x] remax 支持 | support for remax
13 |
14 | ## 概述 | Overview
15 | - 适用于 Webpack 4 | For Webpack 4;
16 | - 只支持微信小程序 | Compactable with WeChat MINA only;
17 | - 支持直接为使用 [Remax](https://github.com/remaxjs/remax) 的项目打包 | En duo avec [Remax](https://github.com/remaxjs/remax);
18 | - 可使用各种 pre-processors (e.g. Pug, Stylus, e.t.c.) | Compactable with variant pre-processors;
19 | - 支持 Component | Support MINA Component;
20 | - 支持分包 | Support MINA sub-package packing;
21 | - 自动合并依赖(使用 Webpack 的 `SplitChunksPlugin`) | Merge dependencies into one single file using `SplitChunksPlugin`;
22 | - 自动通过配置文件生成 `app.json` 和页面的 JSON 配置 | Genarate but not hard-coding MINA configuration JSONs;
23 | - 已在生产环境中测试并使用 | Build for/in production.
24 |
25 | ## 配置项 | Plugin Configuration
26 | ```js
27 | {
28 | // 必填,源码目录绝对对路径
29 | // required, absolute path of src directory
30 | basePath: path.join(__dirname, 'src'),
31 | // 选填,是否开启remax支持
32 | // optional, enable remax support
33 | remax: false
34 | }
35 | ```
36 |
37 | ## 开始使用 | Getting Started
38 | 在 Webpack 配置文件中初始化本插件,并将 `entry` 设置成 `() => ({})` 即可开始使用。
39 |
40 | Initialize the plugin and set `entry` to `() => ({})` to get started.
41 |
42 | ```js
43 | // webpack.config.js
44 | const MinaWebpackPlugin = require('mina-webpack-plugin').default
45 | export default {
46 | // ...
47 | entry: () => ({}),
48 | plugins: [
49 | new MinaWebpackPlugin()
50 | ]
51 | }
52 | ```
53 |
54 | [example](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/simple)
55 |
56 | [example avec Remax](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/remax)
57 |
58 | ## `mina-assets-loader`
59 | 直接使用 `mina-assets-loader` 处理静态资源。
60 |
61 | Just let `mina-assets-loader` handle the static assets.
62 |
63 | ```js
64 | // src/pages/Index/index.js
65 | import thePicture from './index.png'
66 |
67 | // webpack.config.js
68 | export default {
69 | // ...
70 | module: {
71 | rules: [
72 | {
73 | test: /\.(png|svg|jpg|gif)$/,
74 | include: /src/,
75 | use: [
76 | {
77 | loader: 'mina-assets-loader'
78 | }
79 | ]
80 | }
81 | ]
82 | }
83 | }
84 | ```
85 |
86 | ## 模板 | Templates
87 | 在页面的主 `entry` 中直接 `import` 对应的模板文件即可。在 module rules 中加入 `mina-assets-loader?template` 以让插件正确处理正确模板。
88 |
89 | Directly `import` the template file in the page `entry` to use templates. In order to let the plugin processing the template, add `mina-assets-loader?template` in module rules.
90 |
91 | ```js
92 | // src/pages/Index/index.js
93 | import './index.pug'
94 |
95 | // webpack.config.js
96 | export default {
97 | // ...
98 | module: {
99 | rules: [
100 | {
101 | test: /\.pug$/,
102 | include: /src/,
103 | use: [
104 | {
105 | loader: 'mina-assets-loader',
106 | options: {
107 | template: true
108 | }
109 | },
110 | {
111 | loader: 'wxml-loader'
112 | },
113 | {
114 | loader: 'pug-html-loader',
115 | options: {
116 | locals: {
117 | basedir: path.resolve(__dirname, '../src')
118 | },
119 | pretty: true,
120 | debug: false,
121 | cache: true,
122 | basedir: resolve('src')
123 | }
124 | }
125 | ]
126 | }
127 | ]
128 | }
129 | }
130 | ```
131 |
132 | ## 样式表与 CSS Modules | Stylesheets and CSS Modules
133 | 在页面的主 `entry` 中直接 `import` 对应的样式表文件即可。在 module rules 中加入 `mina-assets-loader?stylesheets` 以让插件正确处理正确样式表。
134 |
135 | 如需使用 CSS Modules, 开启 `css-loader` 的 `modules` 选项并同时开启 `mina-assets-loader` 的 `stylesheets` 选项与 `cssModules` 选项。
136 |
137 | Directly `import` the stylesheets file in the page `entry` to use templates. In order to let the plugin processing stylesheets, add `mina-assets-loader?stylesheets` in module rules.
138 |
139 | To use CSS Modules, enable `modules` in `css-loader` and enable both `stylesheets` and `cssModules` in `mina-assets-loader`.
140 |
141 | ```js
142 | // src/pages/Index/index.js
143 | import './index.sass'
144 | import style from './index.module.sass'
145 |
146 |
147 | // webpack.config.js
148 | export default {
149 | // ...
150 | module: {
151 | rules: [
152 | {
153 | test: /\.s(a|c)ss$/,
154 | include: /src/,
155 | exclude: /\.module\.s(a|c)ss$/,
156 | use: [
157 | {
158 | loader: 'mina-assets-loader',
159 | options: {
160 | stylesheets: true
161 | }
162 | },
163 | 'extract-loader',
164 | {
165 | loader: 'css-loader',
166 | options: {
167 | url: false
168 | }
169 | },
170 | 'sass-loader'
171 | ]
172 | },
173 | {
174 | test: /\.module\.s(a|c)ss$/,
175 | include: /src/,
176 | use: [
177 | {
178 | loader: 'mina-assets-loader',
179 | options: {
180 | stylesheets: true,
181 | cssModules: true
182 | }
183 | },
184 | {
185 | loader: 'css-loader',
186 | options: {
187 | modules: {
188 | localIdentName: '[name]__[local]___[hash:base64:5]'
189 | },
190 | url: false
191 | }
192 | },
193 | 'sass-loader'
194 | ]
195 | }
196 | ]
197 | }
198 | }
199 | ```
200 |
201 | ## 授权
202 | MIT
203 |
--------------------------------------------------------------------------------
/packages/mina-assets-loader/README.md:
--------------------------------------------------------------------------------
1 | # MinaWebpackPlugin
2 | MINA(微信小程序) Webpack 插件。
3 |
4 | A Webpack plugin for MINA(WeChat MiniProgram).
5 |
6 | - [x] 基础打包 | basic packaging
7 | - [x] 模板打包 | packaging for templates
8 | - [x] 样式表打包与 CSS Modules | packaging for stylesheets and css modules
9 | - [x] 静态资源打包 | packaging for static resources
10 | - [ ] 自定义组件打包 | packaging for components
11 | - [ ] Source Maps
12 | - [x] remax 支持 | support for remax
13 |
14 | ## 概述 | Overview
15 | - 适用于 Webpack 4 | For Webpack 4;
16 | - 只支持微信小程序 | Compactable with WeChat MINA only;
17 | - 支持直接为使用 [Remax](https://github.com/remaxjs/remax) 的项目打包 | En duo avec [Remax](https://github.com/remaxjs/remax);
18 | - 可使用各种 pre-processors (e.g. Pug, Stylus, e.t.c.) | Compactable with variant pre-processors;
19 | - 支持 Component | Support MINA Component;
20 | - 支持分包 | Support MINA sub-package packing;
21 | - 自动合并依赖(使用 Webpack 的 `SplitChunksPlugin`) | Merge dependencies into one single file using `SplitChunksPlugin`;
22 | - 自动通过配置文件生成 `app.json` 和页面的 JSON 配置 | Genarate but not hard-coding MINA configuration JSONs;
23 | - 已在生产环境中测试并使用 | Build for/in production.
24 |
25 | ## 配置项 | Plugin Configuration
26 | ```js
27 | {
28 | // 必填,源码目录绝对对路径
29 | // required, absolute path of src directory
30 | basePath: path.join(__dirname, 'src'),
31 | // 选填,是否开启remax支持
32 | // optional, enable remax support
33 | remax: false
34 | }
35 | ```
36 |
37 | ## 开始使用 | Getting Started
38 | 在 Webpack 配置文件中初始化本插件,并将 `entry` 设置成 `() => ({})` 即可开始使用。
39 |
40 | Initialize the plugin and set `entry` to `() => ({})` to get started.
41 |
42 | ```js
43 | // webpack.config.js
44 | const MinaWebpackPlugin = require('mina-webpack-plugin').default
45 | export default {
46 | // ...
47 | entry: () => ({}),
48 | plugins: [
49 | new MinaWebpackPlugin()
50 | ]
51 | }
52 | ```
53 |
54 | [example](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/simple)
55 |
56 | [example avec Remax](https://github.com/krhougs/mina-webpack-plugin/tree/master/example/remax)
57 |
58 | ## `mina-assets-loader`
59 | 直接使用 `mina-assets-loader` 处理静态资源。
60 |
61 | Just let `mina-assets-loader` handle the static assets.
62 |
63 | ```js
64 | // src/pages/Index/index.js
65 | import thePicture from './index.png'
66 |
67 | // webpack.config.js
68 | export default {
69 | // ...
70 | module: {
71 | rules: [
72 | {
73 | test: /\.(png|svg|jpg|gif)$/,
74 | include: /src/,
75 | use: [
76 | {
77 | loader: 'mina-assets-loader'
78 | }
79 | ]
80 | }
81 | ]
82 | }
83 | }
84 | ```
85 |
86 | ## 模板 | Templates
87 | 在页面的主 `entry` 中直接 `import` 对应的模板文件即可。在 module rules 中加入 `mina-assets-loader?template` 以让插件正确处理正确模板。
88 |
89 | Directly `import` the template file in the page `entry` to use templates. In order to let the plugin processing the template, add `mina-assets-loader?template` in module rules.
90 |
91 | ```js
92 | // src/pages/Index/index.js
93 | import './index.pug'
94 |
95 | // webpack.config.js
96 | export default {
97 | // ...
98 | module: {
99 | rules: [
100 | {
101 | test: /\.pug$/,
102 | include: /src/,
103 | use: [
104 | {
105 | loader: 'mina-assets-loader',
106 | options: {
107 | template: true
108 | }
109 | },
110 | {
111 | loader: 'wxml-loader'
112 | },
113 | {
114 | loader: 'pug-html-loader',
115 | options: {
116 | locals: {
117 | basedir: path.resolve(__dirname, '../src')
118 | },
119 | pretty: true,
120 | debug: false,
121 | cache: true,
122 | basedir: resolve('src')
123 | }
124 | }
125 | ]
126 | }
127 | ]
128 | }
129 | }
130 | ```
131 |
132 | ## 样式表与 CSS Modules | Stylesheets and CSS Modules
133 | 在页面的主 `entry` 中直接 `import` 对应的样式表文件即可。在 module rules 中加入 `mina-assets-loader?stylesheets` 以让插件正确处理正确样式表。
134 |
135 | 如需使用 CSS Modules, 开启 `css-loader` 的 `modules` 选项并同时开启 `mina-assets-loader` 的 `stylesheets` 选项与 `cssModules` 选项。
136 |
137 | Directly `import` the stylesheets file in the page `entry` to use templates. In order to let the plugin processing stylesheets, add `mina-assets-loader?stylesheets` in module rules.
138 |
139 | To use CSS Modules, enable `modules` in `css-loader` and enable both `stylesheets` and `cssModules` in `mina-assets-loader`.
140 |
141 | ```js
142 | // src/pages/Index/index.js
143 | import './index.sass'
144 | import style from './index.module.sass'
145 |
146 |
147 | // webpack.config.js
148 | export default {
149 | // ...
150 | module: {
151 | rules: [
152 | {
153 | test: /\.s(a|c)ss$/,
154 | include: /src/,
155 | exclude: /\.module\.s(a|c)ss$/,
156 | use: [
157 | {
158 | loader: 'mina-assets-loader',
159 | options: {
160 | stylesheets: true
161 | }
162 | },
163 | 'extract-loader',
164 | {
165 | loader: 'css-loader',
166 | options: {
167 | url: false
168 | }
169 | },
170 | 'sass-loader'
171 | ]
172 | },
173 | {
174 | test: /\.module\.s(a|c)ss$/,
175 | include: /src/,
176 | use: [
177 | {
178 | loader: 'mina-assets-loader',
179 | options: {
180 | stylesheets: true,
181 | cssModules: true
182 | }
183 | },
184 | {
185 | loader: 'css-loader',
186 | options: {
187 | modules: {
188 | localIdentName: '[name]__[local]___[hash:base64:5]'
189 | },
190 | url: false
191 | }
192 | },
193 | 'sass-loader'
194 | ]
195 | }
196 | ]
197 | }
198 | }
199 | ```
200 |
201 | ## 授权
202 | MIT
203 |
--------------------------------------------------------------------------------