UNPKG

7.66 kBJavaScriptView Raw
1'use strict'
2
3const path = require('path')
4const config = require('../config')
5const vueLoaderConfig = require('./loaders/vue-loader.conf')
6const { getEntries, isInstalled } = require('../libs/utils')
7const { splitSNC } = require('../libs/hybrid')
8const paths = config.paths
9const tsImportPluginFactory = require('ts-import-plugin')
10
11const isProd = process.env.NODE_ENV === 'production'
12const maraConf = require(paths.marauder)
13const shouldUseSourceMap = isProd && !!maraConf.sourceMap
14
15let tsImportLibs = []
16if (maraConf.tsImportLibs) {
17 if (Array.isArray(maraConf.tsImportLibs)) {
18 tsImportLibs = tsImportLibs.concat(maraConf.tsImportLibs)
19 } else {
20 throw Error('marauder.config.js中的tsImportLibs必须是Array类型!')
21 }
22}
23
24module.exports = function(entry, type) {
25 const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin')
26 const { styleLoaders } = require('./loaders/style-loader')
27 const {
28 babelLoader,
29 babelExternalMoudles
30 } = require('./loaders/babel-loader')
31 const isLib = entry == '__LIB__'
32 const ASSETS = isLib ? '' : config.assetsDir
33 const entryGlob = `src/view/${entry}/index.@(ts|js)`
34 const { vueRuntimeOnly } = config.compiler
35 const isHybridMode = config.build.env.raw['jsbridgeBuildType'] === 'app'
36 const isDevOrBuildCmd = type === 'dev' || type === 'build'
37 let entryConf = {}
38 let externals = []
39
40 const shouldSNCHoisting =
41 isDevOrBuildCmd &&
42 isHybridMode &&
43 config.compiler.splitSNC &&
44 isInstalled('@mfelibs/universal-framework')
45
46 // hybrid SDK 提升,以尽快建立 jsbridge
47 if (shouldSNCHoisting) {
48 const sncConf = splitSNC(entryGlob)
49
50 // 使用拆分后的 entry 配置
51 entryConf = sncConf.entry
52 externals.push(...sncConf.externals)
53 } else {
54 entryConf = getEntries(entryGlob, require.resolve('./polyfills'))
55 }
56
57 const baseConfig = {
58 // dev, build 环境依赖 base.entry,务必提供
59 entry: entryConf,
60 output: {
61 path: paths.dist,
62 // 统一使用 POSIX 风格拼接路径
63 // webpack 将会处理平台差异
64 // 如果使用 path.join 在 Windows 上会出现路径异常
65 filename: path.posix.join(ASSETS, 'js/[name].js'),
66 chunkFilename: path.posix.join(ASSETS, 'js/[name].async.js')
67 },
68 resolve: {
69 // disable symlinks
70 symlinks: false,
71 // js first
72 extensions: [
73 '.js',
74 '.ts',
75 '.jsx',
76 '.tsx',
77 '.sn',
78 '.vue',
79 '.json',
80 '.mjs'
81 ],
82 // https://doc.webpack-china.org/configuration/resolve/#resolve-mainfields
83 // source 为自定义拓展属性,表示源码入口
84 mainFields: ['source', 'browser', 'module', 'main'],
85 modules: ['node_modules'],
86 alias: {
87 // 使用 `~` 作为 src 别名
88 // 使用特殊符号防止与 npm 包冲突
89 // import '~/css/style.css'
90 '~': paths.src,
91 vue$: `vue/dist/vue${vueRuntimeOnly ? '.runtime' : ''}.esm.js`,
92 'babel-runtime': path.dirname(
93 require.resolve('babel-runtime/package.json')
94 ),
95 // Support React Native Web
96 // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
97 'react-native': 'react-native-web'
98 },
99 plugins: [
100 // Prevents users from importing files from outside of src/ (or node_modules/).
101 // This often causes confusion because we only process files within src/ with babel.
102 // To fix this, we prevent you from importing files out of src/ -- if you'd like to,
103 // please link the files into your node_modules/ and let module-resolution kick in.
104 // Make sure your source files are compiled, as they will not be processed in any way.
105 new ModuleScopePlugin(paths.src, [paths.packageJson])
106 ]
107 },
108 resolveLoader: {
109 modules: [paths.ownNodeModules, paths.nodeModules]
110 },
111 module: {
112 // makes missing exports an error instead of warning
113 strictExportPresence: false,
114 rules: [
115 // Disable require.ensure as it's not a standard language feature.
116 // 为了兼容 bundle-loader 暂时不启用
117 // { parser: { requireEnsure: false } },
118 {
119 oneOf: [
120 ...styleLoaders({
121 sourceMap: shouldUseSourceMap,
122 extract: isProd && type !== 'mc',
123 library: isLib
124 }),
125 {
126 test: /\.(bmp|png|jpe?g|gif|svg)(\?.*)?$/,
127 loader: 'url-loader',
128 options: {
129 limit: 10000,
130 name: path.posix.join(ASSETS, 'img/[name].[hash:8].[ext]')
131 }
132 },
133 {
134 test: /\.ejs$/,
135 loader: 'marauder-ejs-loader'
136 },
137 {
138 test: /\.art$/,
139 loader: 'art-template-loader'
140 },
141 {
142 test: /\.(vue|sn)$/,
143 loader: 'vue-loader',
144 options: vueLoaderConfig
145 },
146 {
147 test: /\.mustache$/,
148 loader: 'mustache-loader'
149 },
150 // Process JS with Babel.
151 babelLoader(isProd),
152 {
153 test: /\.tsx?$/,
154 // require.resolve 将会检查模块是否存在
155 // ts-loader 为可选配置,所以这里不使用 require.resolve
156 loader: 'ts-loader',
157 include: babelExternalMoudles,
158 options: {
159 appendTsSuffixTo: [/\.vue$/],
160 transpileOnly: true,
161 getCustomTransformers: () => ({
162 before: [tsImportPluginFactory(tsImportLibs)]
163 }),
164 compilerOptions: {
165 module: 'ESNext'
166 }
167 }
168 },
169 {
170 test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
171 loader: 'file-loader',
172 options: {
173 name: path.posix.join(ASSETS, 'fonts/[name].[hash:8].[ext]')
174 }
175 },
176 {
177 // Exclude `js` files to keep "css" loader working as it injects
178 // it's runtime that would otherwise processed through "file" loader.
179 // Also exclude `html` and `json` extensions so they get processed
180 // by webpacks internal loaders.
181 loader: 'file-loader',
182 exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
183 options: {
184 name: path.posix.join(ASSETS, 'media/[name].[hash:8].[ext]')
185 }
186 },
187 {
188 test: /\.(html)$/,
189 use: {
190 loader: 'html-loader',
191 options: {
192 attrs: [':src', ':data-src']
193 }
194 }
195 }
196 ]
197 }
198 ]
199 },
200 plugins: [],
201 externals: externals,
202 // Some libraries import Node modules but don't use them in the browser.
203 // Tell Webpack to provide empty mocks for them so importing them works.
204 node: {
205 // prevent webpack from injecting useless setImmediate polyfill because Vue
206 // source contains it (although only uses it if it's native).
207 setImmediate: false,
208 dgram: 'empty',
209 fs: 'empty',
210 net: 'empty',
211 tls: 'empty',
212 child_process: 'empty'
213 }
214 }
215
216 if (isHybridMode) {
217 const { SinaHybridPlugin } = require('../libs/hybrid')
218
219 // 确保在 copy Files 之前
220 baseConfig.plugins.push(
221 new SinaHybridPlugin({
222 entry: entry,
223 splitSNC: shouldSNCHoisting
224 })
225 )
226 }
227
228 return baseConfig
229}